如何在 Kotlin 中加载

how to have loading in Kotlin

我的 MainActivity 包含一个加载 4 个片段的 ViewPager,每个片段应该从服务器加载大量数据。

所以当我的应用程序第一次想要 运行 时,它几乎需要超过 3 秒和其他时间(例如,如果你退出应用程序但没有从你的 'recently app' window 并重新打开它)它需要将近 1 秒。

加载时显示白屏。

有没有办法在数据准备好之前显示白屏,而不是显示我自己的图像? 像启动页之类的东西?

如果您在主线程上执行长时间 运行 操作,您可能会遇到 ANR crash.

每个片段的布局都应该有一个最初可见的加载视图和数据视图。像这样:

(不是代码)

FrameLayout
    loading_view (can show a progress spinner or something, size is match parent)
    content_view (probably a RecyclerView, initial visibility=GONE, size is match parent)
/FrameLayout

您需要在后台线程或协同程序上执行长 运行 操作,然后在数据准备好在 UI 中显示时交换这两个视图的可见性。

您不应直接在 Fragment 代码中处理数据加载,因为 Fragment 是一个 UI 控制器。 Android Jetpack 库为此提供了 ViewModel class。您可以像这样设置您的 ViewModel。在这个例子中,MyData 可以是任何东西。在你的情况下,它可能是一个列表或一组东西。

class MyBigDataViewModel(application: Application): AndroidViewModel(application) {

    private val _myBigLiveData = MutableLiveData<MyData>()
    val myBigLiveData: LiveData<MyData>() = _myBigLiveData 

    init {
        loadMyBigData()
    }

    private fun loadMyBigData() {
        viewModelScope.launch { // start a coroutine in the main UI thread
            val myData: MyData = withContext(Dispatchers.Default) { 
                // code in this block is done on background coroutine
                // Calculate MyData here and return it from lambda
                // If you have a big for-loop, you might want to call yield()
                // inside the loop to allow this job to be cancelled early if
                // the Activity is closed before loading was finished.
                //...
                return@withContext calculatedData
            }

            // LiveData can only be accessed from the main UI thread so
            // we do it outside the withContext block
            _myBigLiveData.value = myData
        }
    }

}

然后在您的片段中,观察实时数据以在准备就绪时更新 UI。下面使用 fragment-ktx 库,您需要将其添加到您的项目中。您绝对应该阅读 documentation on ViewModel.

class MyFragment: Fragment() {

    // ViewModels should not be instantiated directly, or they won't be scoped to the
    // UI life cycle correctly. The activityViewModels delegate handles instantiation for us.
    private val model: MyBigDataViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        model.myBigLiveData.observe(this, Observer<MyData> { myData ->
            loading_view.visibility = View.GONE
            content_view.visibility = View.VISIBLE
            // use myData to update the view content
        })
    }
}