通过视图模型在片段之间共享数据

时间:2019-03-27 06:56:06

标签: android android-jetpack android-viewmodel

根据https://developer.android.com/topic/libraries/architecture/viewmodel中“在片段之间共享数据”部分,我们被告知在活动范围内创建ViewModel并在片段之间共享是一个可行的方法。

这是在ViewModel中设置值的片段

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

这是使用属性集的详细片段

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}

这是ViewModel

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

我的问题很简单。假设MasterFragment在单击按钮时在ViewModel中设置了一个值,那么当系统杀死我们的应用程序并重新启动它之后,当我们访问该值时,我们将如何恢复该值。

由于我们在MasterFragment上单击按钮进行设置,因此我们的DetailFragment将看不到该值。为了更好地理解该问题,请考虑我们有Fragment A,B,C和D,它们共享一个ViewModel,该ViewModel的值是Fragment A B和C一起计算出的值,并将其放在ViewModel中,以便Fragment D访问。

现在,当系统终止并重新创建应用程序Fragment D时,该值将不再可用。

如果不依靠肮脏的代码,OnSaveInstance也将无济于事。对于简单的情况,是的,但就像FragmentA B和C一起产生值的情况一样,在这种情况下,OnSaveInstance会出现问题。

OnSaveInstance应该位于ViewModel内部,但是我不认为是这种情况。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

如果在重置或取消应用程序后仍希望获得存储的价值,则需要将数据保存到SharedPreferences或内部SqLite数据库中,并在应用程序启动后将其还原。

答案 1 :(得分:1)

  

ViewModel对象的范围是获取ViewModel时传递给ViewModelProvider的生命周期。 ViewModel会一直保留在内存中,直到其生命周期范围永久消失:在活动中,活动结束时;在片段中,活动断开时。

You can check it here

  

我的问题很简单。假设MasterFragment在buttonClick的ViewModel中设置了一个值,那么当系统杀死我们的应用程序并重新启动它之后,在访问它时我们将如何恢复该值?

如果应用程序被用户或系统杀死或重新启动,则无法恢复该值。

要解决从活动A,活动B和活动C收集数据并将其显示在活动D中的目的,即使应用程序被终止或重新启动,您也可以从以下任意一种方法中进行选择:
1. SharedPreference
2.本地数据库Room或SQLite
3.将数据存储在文件中

我建议您对小数据使用SharedPreference,对大型和复杂数据使用Room。

简而言之,ViewModel临时存储数据以适应方向变化(无需编写onSaveInstanceStateonRestoreInstanceState的代码),并在Activity和Fragments之间共享数据。如果活动被破坏或片段被分离,数据将丢失。

答案 2 :(得分:0)

对于那些在那里使用Kotlin的人,请尝试以下方法:

  • 将androidx ViewModel and LiveData库添加到gradle文件中

  • 像这样在片段中调用视图模型:

     class MainFragment : Fragment() {
    
       private lateinit var viewModel: ViewModel
    
       override fun onActivityCreated(savedInstanceState: Bundle?) {
           super.onActivityCreated(savedInstanceState)
    
           // kotlin does not have a getActivity() built in method instead we use activity, which is null-safe
           activity?.let {
               viemModel = ViewModelProvider(it).get(SharedViewModel::class.java)
           }
       }
    }