无法在 Activity 和 Fragment 之间共享 Viewmodel:
Can't share Viewmodel between Activity and Fragment:
Android Studio 3.6
这是我的视图模型:
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
class BluetoothPageViewModel(application: Application) : AndroidViewModel(application) {
private val isSearchingTableModeLiveData = MutableLiveData<Boolean>()
private val isInitModeLiveData = MutableLiveData<Boolean>()
private val errorMessageLiveData = MutableLiveData<String>()
private val toastMessageLiveData = MutableLiveData<String>()
fun isInitModeLiveData(): LiveData<Boolean> {
return isInitModeLiveData
}
fun isSearchingTableModeLiveData(): LiveData<Boolean> {
return isSearchingTableModeLiveData
}
fun getErrorMessageLiveData(): LiveData<String> {
return errorMessageLiveData
}
fun getToastMessageLiveData(): LiveData<String> {
return toastMessageLiveData
}
此处片段订阅此 viewmodel 并成功调用 Observer.onChanged()
class BluetoothPageFragment : Fragment() {
private lateinit var bluetoothPageViewModel: BluetoothPageViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
dataBinding =
DataBindingUtil.inflate(inflater, R.layout.bluetooth_page_fragment, container, false)
val view = dataBinding.getRoot()
dataBinding.setHandler(this)
init()
return view
}
private fun init() {
val context = this.context
val viewViewModelProvider = ViewModelProviders.of(this)
bluetoothPageViewModel = viewViewModelProvider.get(BluetoothPageViewModel::class.java)
bluetoothPageViewModel.isInitModeLiveData().observe(this, // SUCCESS CALL
Observer<Boolean> { isInitMode ->
})
}
这里是我的 activity 订阅这个 viewmodel 并且 NOT call Observer.onChanged()
import androidx.lifecycle.ViewModelProviders
class QRBluetoothSwipeActivity : AppCompatActivity() {
private lateinit var bluetoothPageViewModel: BluetoothPageViewModel
private fun init() {
val viewViewModelProvider = ViewModelProviders.of(this)
bluetoothPageViewModel = viewViewModelProvider.get(BluetoothPageViewModel::class.java)
val customFragmentStateAdapter = CustomFragmentStateAdapter(this)
customFragmentStateAdapter.addFragment(QrPageFragment())
bluetoothPageFragment = BluetoothPageFragment()
customFragmentStateAdapter.addFragment(bluetoothPageFragment)
dataBinding.viewPager2.adapter = customFragmentStateAdapter
initLogic()
}
private fun initLogic() {
dataBinding.viewPager2.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
positionObservable.set(position)
}
})
bluetoothPageViewModel.getToastMessageLiveData() // this not call
.observe(this,
Observer<String> { message ->
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
})
}
为什么不打电话给 getToastMessageLiveData()
?
您在 activity 和片段中都调用了 ViewModelProviders.of(this)
,但这是不同的上下文。因此,在您的情况下,您实例化了 2 个不同的 BluetoothPageViewModel 实例,因此未调用 onChanged
回调。
为了在 activity 和 Fragment 之间共享一个实例,您应该从同一上下文中获取 viewModelProvider。
在你的 activity 中:
ViewModelProviders.of(this)
在你的片段中:
ViewModelProviders.of(activity)
或
activity?.let {
val bluetoothPageViewModel = ViewModelProviders.of(it).get(BluetoothPageViewModel::class.java)
bluetoothPageViewModel.isInitModeLiveData().observe(this, // SUCCESS CALL
Observer<Boolean> { isInitMode ->
})
}
在这两种情况下,您都在使用
ViewModelProviders.of(this)
这意味着您希望此视图模型具有不同的范围。一个来自 Activity Scope,一个来自 Fragment 范围。如果你想分享它。
如果你想共享视图模型,你必须使用单一范围。我建议使用更大元素的范围,在本例中为 activity。
在片段中你应该调用
ViewModelProviders.of(activity)
这应该可以解决您的问题。
Android Studio 3.6
这是我的视图模型:
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
class BluetoothPageViewModel(application: Application) : AndroidViewModel(application) {
private val isSearchingTableModeLiveData = MutableLiveData<Boolean>()
private val isInitModeLiveData = MutableLiveData<Boolean>()
private val errorMessageLiveData = MutableLiveData<String>()
private val toastMessageLiveData = MutableLiveData<String>()
fun isInitModeLiveData(): LiveData<Boolean> {
return isInitModeLiveData
}
fun isSearchingTableModeLiveData(): LiveData<Boolean> {
return isSearchingTableModeLiveData
}
fun getErrorMessageLiveData(): LiveData<String> {
return errorMessageLiveData
}
fun getToastMessageLiveData(): LiveData<String> {
return toastMessageLiveData
}
此处片段订阅此 viewmodel 并成功调用 Observer.onChanged()
class BluetoothPageFragment : Fragment() {
private lateinit var bluetoothPageViewModel: BluetoothPageViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
dataBinding =
DataBindingUtil.inflate(inflater, R.layout.bluetooth_page_fragment, container, false)
val view = dataBinding.getRoot()
dataBinding.setHandler(this)
init()
return view
}
private fun init() {
val context = this.context
val viewViewModelProvider = ViewModelProviders.of(this)
bluetoothPageViewModel = viewViewModelProvider.get(BluetoothPageViewModel::class.java)
bluetoothPageViewModel.isInitModeLiveData().observe(this, // SUCCESS CALL
Observer<Boolean> { isInitMode ->
})
}
这里是我的 activity 订阅这个 viewmodel 并且 NOT call Observer.onChanged()
import androidx.lifecycle.ViewModelProviders
class QRBluetoothSwipeActivity : AppCompatActivity() {
private lateinit var bluetoothPageViewModel: BluetoothPageViewModel
private fun init() {
val viewViewModelProvider = ViewModelProviders.of(this)
bluetoothPageViewModel = viewViewModelProvider.get(BluetoothPageViewModel::class.java)
val customFragmentStateAdapter = CustomFragmentStateAdapter(this)
customFragmentStateAdapter.addFragment(QrPageFragment())
bluetoothPageFragment = BluetoothPageFragment()
customFragmentStateAdapter.addFragment(bluetoothPageFragment)
dataBinding.viewPager2.adapter = customFragmentStateAdapter
initLogic()
}
private fun initLogic() {
dataBinding.viewPager2.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
positionObservable.set(position)
}
})
bluetoothPageViewModel.getToastMessageLiveData() // this not call
.observe(this,
Observer<String> { message ->
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
})
}
为什么不打电话给 getToastMessageLiveData()
?
您在 activity 和片段中都调用了 ViewModelProviders.of(this)
,但这是不同的上下文。因此,在您的情况下,您实例化了 2 个不同的 BluetoothPageViewModel 实例,因此未调用 onChanged
回调。
为了在 activity 和 Fragment 之间共享一个实例,您应该从同一上下文中获取 viewModelProvider。
在你的 activity 中:
ViewModelProviders.of(this)
在你的片段中:
ViewModelProviders.of(activity)
或
activity?.let {
val bluetoothPageViewModel = ViewModelProviders.of(it).get(BluetoothPageViewModel::class.java)
bluetoothPageViewModel.isInitModeLiveData().observe(this, // SUCCESS CALL
Observer<Boolean> { isInitMode ->
})
}
在这两种情况下,您都在使用
ViewModelProviders.of(this)
这意味着您希望此视图模型具有不同的范围。一个来自 Activity Scope,一个来自 Fragment 范围。如果你想分享它。 如果你想共享视图模型,你必须使用单一范围。我建议使用更大元素的范围,在本例中为 activity。 在片段中你应该调用
ViewModelProviders.of(activity)
这应该可以解决您的问题。