【发布时间】:2018-09-07 14:37:22
【问题描述】:
在编写 Android 应用时,我遇到了动画卡顿的问题。我使用 AHBottomNavigation 进行导航,FragNav 用于交换片段,FlexibleAdapter 用于 RecyclerView。 该应用程序由一个活动和五个片段构建而成。当我尝试切换到应用程序中的第一个片段时,BottomNavigation 动画冻结了片刻。它看起来非常难看。我第二次选择相同的片段时,一切都很顺利。在我看来,初始化片段中的视图是错误的,但我不知道如何以不同的方式进行。
AHBottomNavigation https://github.com/aurelhubert/ahbottomnavigation
FragNav https://github.com/ncapdevi/FragNav
灵活适配器https://github.com/davideas/FlexibleAdapter
片段
class GradeFragment : BaseFragment(), GradeView {
@Inject
lateinit var presenter: GradePresenter
private val gradeAdapter = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
companion object {
fun newInstance() = GradeFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_grade, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
presenter.run {
attachView(this@GradeFragment)
loadData()
}
}
override fun initView() {
gradeAdapter.run {
isAutoCollapseOnExpand = true
isAutoScrollOnExpand = true
setOnUpdateListener { presenter.onUpdateDataList(it) }
setOnItemClickListener { position ->
getItem(position).let {
if (it is GradeItem) {
GradeDialog.newInstance(it.grade).show(fragmentManager, it.toString())
}
}
}
}
gradeRecycler.run {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = gradeAdapter
}
gradeSwipe.setOnRefreshListener { presenter.loadData(forceRefresh = true) }
}
override fun updateData(data: List<GradeHeader>) {
gradeAdapter.updateDataSet(data, true)
}
override fun isViewEmpty(): Boolean = gradeAdapter.isEmpty
override fun showEmptyView(show: Boolean) {
gradeEmpty.visibility = if (show) VISIBLE else GONE
}
override fun showProgress(show: Boolean) {
gradeProgress.visibility = if (show) VISIBLE else GONE
}
override fun setRefresh(show: Boolean) {
gradeSwipe.isRefreshing = show
}
演示者
class GradePresenter @Inject constructor(
private val errorHandler: ErrorHandler,
private val schedulers: SchedulersManager,
private val gradeRepository: GradeRepository,
private val sessionRepository: SessionRepository) : BasePresenter<GradeView>(errorHandler) {
override fun attachView(view: GradeView) {
super.attachView(view)
view.initView()
}
fun loadData(forceRefresh: Boolean = false) {
disposable.add(sessionRepository.getSemesters()
.map { it.single { semester -> semester.current } }
.flatMap { gradeRepository.getGrades(it, forceRefresh) }
.map { it.groupBy { grade -> grade.subject } }
.map { createGradeItems(it) }
.subscribeOn(schedulers.backgroundThread())
.observeOn(schedulers.mainThread())
.doFinally { view?.setRefresh(false) }
.doOnSuccess { if (it.isEmpty()) view?.showEmptyView(true) }
.doOnError { view?.run { if (isViewEmpty()) showEmptyView(true) } }
.subscribe({ view?.updateData(it) }) { errorHandler.proceed(it) })
}
private fun createGradeItems(items: Map<String, List<Grade>>): List<GradeHeader> {
return items.map {
val gradesAverage = calcAverage(it.value)
GradeHeader().apply {
subject = it.key
average = view?.run {
if (gradesAverage == 0f) emptyAverageString()
else averageString().format(gradesAverage)
}.orEmpty()
number = view?.gradeNumberString(it.value.size).orEmpty()
subItems = (it.value.map { item ->
GradeItem().apply {
grade = item
weightString = view?.weightString().orEmpty()
valueColor = getValueColor(item.value)
}
})
}
}
}
fun onUpdateDataList(size: Int) {
if (size != 0) view?.showProgress(false)
}
【问题讨论】:
-
尝试通过使用时间测量日志来确定导致延迟的呼叫。常见的违规者可能是您的
loadData或适配器onBindViewHolder -
loadData在不同的线程中执行,不应影响 ui 线程。onBindViewHolder很简单,我只设置了已经锤炼的文字,没有逻辑。我使用 Androi Profiller 查看单击时会发生什么,这是结果ibb.co/cys0oU -
找了几天原因,大概找到了罪魁祸首。当 android 膨胀片段视图时,就会发生堵塞。该视图很简单,但它包含一个 Recycler View,它会导致堵塞。从 xml 中删除后,交换片段很顺利。但是,这不是解决方案,因为我需要在此视图中使用 Recyler 视图。
标签: android performance android-fragments kotlin bottomnavigationview