【问题标题】:Initialization of a fragment causes the animation lag片段的初始化导致动画滞后
【发布时间】: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


【解决方案1】:

几天后,我通过将SDK更新到版本28设法解决了这个问题。RecyclerView在充气时不再导致动画卡顿

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 2012-03-10
    • 2022-08-23
    • 1970-01-01
    • 2013-07-26
    相关资源
    最近更新 更多