ViewModel片段在屏幕旋转时重新创建

时间:2020-07-26 19:12:17

标签: android kotlin android-fragments kotlin-coroutines android-viewmodel

我正在使用最新的Android体系结构组件构建应用程序。我正在将firebase firestore用作带有jetpack导航(底部导航)的数据库。我能够成功显示数据库中的数据。但是每当我旋转mt屏幕时,商店片段就会重新创建并向DB发出请求。

回购

    override fun getAllStores() = callbackFlow<State<List<Store>>> {
    // Emit loading state
    send(State.loading())

    val listener = remoteDB.collection(Constants.COLLECTION_STORES)
        .addSnapshotListener { querySnapshot, exception ->
            querySnapshot?.toObjects(Store::class.java)?.let { store ->
                // Emit success state with data
                offer(State.success(store))
            }
            exception?.let {
                // emit exception with message
                offer(State.failed(it.message!!))
                cancel()
            }
        }
    awaitClose {
        listener.remove()
        cancel()
    }

}.catch {
    // Thrown exception on State Failed
    emit(State.failed(it.message.toString()))
}.flowOn(Dispatchers.IO)

ViewModel

@ExperimentalCoroutinesApi
@InternalCoroutinesApi
class StoreViewModel(private val repository: DBInterface = Repo()) : ViewModel() {

fun getAllStores() = repository.getAllStores()

}

存储片段

@ExperimentalCoroutinesApi
@InternalCoroutinesApi
class StoreFragment : Fragment(R.layout.fragment_store) {
private lateinit var storeAdapter: StoreAdapter
private val viewModel: StoreViewModel by viewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    (activity as MainActivity).supportActionBar?.title = getString(R.string.store_title)

    setUpRV()

    // get all stores
    lifecycleScope.launch {
        getAllStores()
    }

}

private suspend fun getAllStores() {
    viewModel.getAllStores().collect { state ->
        when (state) {
            is State.Loading -> {
                store_progress.show()
            }

            is State.Success -> {
                storeAdapter.differ.submitList(state.data)
                store_progress.animate().alpha(0f)
                        .withEndAction {
                            store_rv.animate().alpha(1f)
                            store_progress.hide()
                        }

            }
            is State.Failed -> {
                store_progress.hide()
                activity?.toast("Failed! ${state.message}")
            }
        }
    }
}

private fun setUpRV() {
    storeAdapter = StoreAdapter()
    store_rv.apply {
        adapter = storeAdapter
        addItemDecoration(SpacesItemDecorator(16))
    }
}

}

主要活动(导航图)

@InternalCoroutinesApi
@ExperimentalCoroutinesApi
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setSupportActionBar(toolbar)

    // init bottom navigation
    bottom_navigation.setupWithNavController(nav_host_fragment.findNavController())
   
}
}

每次它都会重新创建我的片段。我不想使用方法保存或保留任何视图。因为ViewModel用于保护屏幕旋转时的视图。请让我知道任何提示和技巧。在此先感谢;)

2 个答案:

答案 0 :(得分:2)

Flow本身不是有状态的-这是它与LiveData之间的主要区别。这意味着collect完成后,下一个collect从头开始callbackFlow

这正是lifecycle-livedata-ktx工件包含asLiveData()扩展名的原因,该扩展名允许您在保持{的有状态(和生命周期)属性的同时,继续在存储库层使用Flow {1}}用于您的用户界面:

LiveData

您将更改UI代码以继续使用@ExperimentalCoroutinesApi @InternalCoroutinesApi class StoreViewModel(private val repository: DBInterface = Repo()) : ViewModel() { fun getAllStores() = repository.getAllStores().asLiveData() } LiveData

科特林正在a shareIn operation上进行研究,允许您的observe()保存ViewModel的状态。这样一来,当调用Flow的Fragment / Activity被销毁并重新创建时,您就可以在应用的所有层使用Flow,而无需从头开始重新查询信息。

答案 1 :(得分:1)

您可以将android:configChanges="orientation|screenSize|screenLayout"添加到活动清单中。这样可以防止在方向更改时重新启动。

选中此sitehere都是Som信息。