首页 > 解决方案 > ViewModel 中的延迟初始化方法

问题描述

我在 Github 有以下项目:https ://github.com/AliRezaeiii/TMDb-Paging

由于数据源未初始化,我必须在 ViewModel 中发布延迟调用方法:

abstract class DetailViewModel(private val item: TmdbItem) : BaseViewModel() {

    private val handler = Handler(Looper.getMainLooper())

    val trailers: ObservableList<Video> = ObservableArrayList()
    val isTrailersVisible = ObservableBoolean(false)

    private val _cast = MutableLiveData<List<Cast>>()
    val cast: LiveData<List<Cast>> = _cast

    val isCastVisible = ObservableBoolean(false)

    init {
        handler.postDelayed({
            showTrailers()
            showCast()
        }, 100)
    }

    protected abstract fun getTrailers(id: Int): Observable<List<Video>>

    protected abstract fun getCast(id: Int): Observable<List<Cast>>

    private fun showTrailers() {
        EspressoIdlingResource.increment() // App is busy until further notice
        compositeDisposable.add(getTrailers(item.id)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doFinally {
                    if (!EspressoIdlingResource.getIdlingResource().isIdleNow) {
                        EspressoIdlingResource.decrement() // Set app as idle.
                    }
                }
                .subscribe({ videos ->
                    if (videos.isNotEmpty()) {
                        isTrailersVisible.set(true)
                    }
                    with(trailers) {
                        clear()
                        addAll(videos)
                    }
                }
                ) { throwable -> Timber.e(throwable) })
    }

    private fun showCast() {
        EspressoIdlingResource.increment() // App is busy until further notice
        compositeDisposable.add(getCast(item.id)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doFinally {
                    if (!EspressoIdlingResource.getIdlingResource().isIdleNow) {
                        EspressoIdlingResource.decrement() // Set app as idle.
                    }
                }
                .subscribe({ cast ->
                    if (cast.isNotEmpty()) {
                        isCastVisible.set(true)
                    }
                    this._cast.postValue(cast)
                }
                ) { throwable -> Timber.e(throwable) })
    }
}

这是我的片段:

abstract class DetailFragment<T : TmdbItem>
    : BaseDaggerFragment(), CastClickCallback {

    protected abstract fun getViewModel(): DetailViewModel

    protected abstract fun getLayoutId(): Int

    protected abstract fun initViewBinding(root: View): ViewDataBinding

    protected abstract fun getTmdbItem(): T

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        val viewModel = getViewModel()

        val root = inflater.inflate(getLayoutId(), container, false)

        initViewBinding(root).apply {
            setVariable(BR.vm, viewModel)
            lifecycleOwner = viewLifecycleOwner
        }

        with(root) {

            with(activity as AppCompatActivity) {
                setupActionBar(details_toolbar) {
                    setDisplayShowTitleEnabled(false)
                    setDisplayHomeAsUpEnabled(true)
                    setDisplayShowHomeEnabled(true)
                }
            }

            summary_label.visibleGone(getTmdbItem().overview.trim().isNotEmpty())

            // Make the MotionLayout draw behind the status bar
            details_motion.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                    View.SYSTEM_UI_FLAG_LAYOUT_STABLE

            summary.setOnClickListener {
                val maxLine = resources.getInteger(R.integer.max_lines)
                summary.maxLines = if (summary.maxLines > maxLine) maxLine else Int.MAX_VALUE
            }

            viewModel.cast.observe(viewLifecycleOwner, Observer {
                it?.apply {
                    val adapter = CastAdapter(it, this@DetailFragment)
                    cast_list.apply {
                        setHasFixedSize(true)
                        cast_list.adapter = adapter
                    }
                }
            })

            with(details_rv) {
                postDelayed({ scrollTo(0, 0) }, 100)
            }
        }

        return root
    }
}

和 BaseDaggerFragment :

open class BaseDaggerFragment : DaggerFragment() {

    @Inject
    lateinit var dataSource: RemoteDataSource
}

可能是比以下更好的解决方案:

init {
            handler.postDelayed({
                showTrailers()
                showCast()
            }, 100)
        }

标签: androidandroid-jetpackandroid-viewmodel

解决方案


您可以像这样延迟初始化

private val users:MutableLiveData<List<Cast>> by lazy {
    MutableLiveData().also {
       showTrailers()
        showCast()
    }
}

更多细节参考ViewModel


推荐阅读