提问人:Reza Asadian 提问时间:9/25/2023 最后编辑:Reza Asadian 更新时间:9/27/2023 访问量:95
从 FragmentB 返回后,数据绑定对 FragmentA 不起作用
Data binding not working for FragmentA after returning from FragmentB
问:
我的应用程序有两个片段:和 . 将一些连接信息绑定到 UI。信息从广播接收器获取。一开始,数据绑定工作,但当用户转到 然后返回 时,info 不会绑定。HomeFragment
StatusFragment
HomeFragment
HomeFragment
StatusFragment
HomeFragment
HomeFragment、StatusFragment 和 HomeFragmentViewModel 类如下所示:
class HomeFragment : Fragment() {
private var binding: FragmentHomeBinding? = null
private var connectionStatus: String? = "Offline"
private var connectionType: String? = ""
private lateinit var mReceiver: ConnectivityChangeBroadcastReceiver
lateinit var homeFragmentViewModel: HomeFragmentViewModel
lateinit var repo: Repository
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentHomeBinding.inflate(inflater, container, false)
binding?.lifecycleOwner = viewLifecycleOwner
repo = Repository().getInstance()!!
val viewModelFactory = HomeFragmentViewModelFactory(repo)
homeFragmentViewModel =
ViewModelProvider(this, viewModelFactory)[HomeFragmentViewModel::class.java]
binding?.homeFragmentViewModel = homeFragmentViewModel
this.mReceiver = ConnectivityChangeBroadcastReceiver()
mReceiver.mData.observe(this, Observer {
repo.setInfo(mReceiver.getData())
homeFragmentViewModel.getConnectionInfo()
})
homeFragmentViewModel.navToStatusFragment.observe(this, Observer {
if (it==true){
this.findNavController().navigate(R.id.action_homeFragment_to_statusFragment)
homeFragmentViewModel.doneNavigateToStatusFragment()
}
})
return binding?.root
}
override fun onStart() {
super.onStart()
requireActivity().registerReceiver(
mReceiver, IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
repo.setInfo(mReceiver.getData())
}
override fun onStop() {
super.onStop()
requireActivity().unregisterReceiver(mReceiver)
}
}
class StatusFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
requireActivity().onBackPressedDispatcher.addCallback(this){
requireActivity().supportFragmentManager.popBackStack()
}
return inflater.inflate(R.layout.fragment_status, container, false)
}
}
class HomeFragmentViewModel(private val repo: Repository?) : ViewModel() {
private val viewModelJob = Job()
private val _navToStatusFragment = MutableLiveData<Boolean?>()
val navToStatusFragment: LiveData<Boolean?>
get() = _navToStatusFragment
private val _connected = MutableLiveData<String?>()
val connected: LiveData<String?>
get() = _connected
private val _connectionType = MutableLiveData<String?>()
val connectionType: LiveData<String?>
get() = _connectionType
init {
_navToStatusFragment.value = false
}
var isConnected: LiveData<Boolean> = connected.map {
when (it) {
"Online" -> true
else -> false
}
}
fun doneNavigateToStatusFragment(){
_navToStatusFragment.value = false
}
fun navigateToStatusFragment(){
_navToStatusFragment.value = true
}
fun getConnectionInfo() {
when (repo?.getInfo()?.value) {
0 -> {
_connected.value = "Offline"
_connectionType.value = "Check Your Connection"
_connectionDetails.value = null
}
1 -> {
_connected.value = "Online"
_connectionType.value = "Cellular"
_connectionDetails.value = null
}
2 -> {
_connected.value = "Online"
_connectionType.value = "WIFI"
_connectionDetails.value = null
}
3 -> {
_connected.value = "Online"
_connectionType.value = "VPN"
_connectionDetails.value = null
}
}
Log.d("LOGGED", "Info Checked ...")
}
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
}
}
我做了:
- 在 中使用 也
regiterReceiver()
onResume()
- using 代替 for
viewLifeCycleOwner
this
binding.lifeCycleOwner
- 按下后退按钮时使用
popBackStack()
StatusFragment
更新:问题是回到 HomeFragment 后,调用了 onCreateView(),但未调用 HomeFragmentViewModelFactory()!->我需要它来发送新的存储库对象到视图模型
答:
关于您的更新说明:viewModel 在返回片段时不会重新创建,因此不会调用工厂。
您需要了解 viewModel Owner。为了创建一个 viewModel,我们需要一个 which 是一个接口,我们将在稍后看到,并且 , , 和类实现这个接口。这是第一个参数,在您的例子中是 this,这意味着当前片段。ViewModelStoreOwner
activity
fragment
navgraph
navBackStackEntry
ViewModelProvider
这有什么作用?基本上它有一个地图,它保留了创建的 viewModel 的实例,当请求 viewModel 使用时,首先它会查看该地图内部以查看它是否创建了它,如果创建了它,它将返回以前创建的 viewModel,否则它将调用 创建一个新的,之后它将其存储在该地图中以供以后使用。ViewModelStoreOwner
ViewModelProvider
ViewModelFactory
那是什么意思?对于片段,此映射是在 onCreate 回调中创建的,并在 onDestroy 回调(不是 onDestroyView)中销毁,因此当您导航到新片段时,由于该片段尚未销毁,因此 viewModel 仍然存在于此映射中,因此在返回时,将返回之前创建的映射中的那个。
可能的解决方案:在 viewModel 中创建一个函数并将 repo 传递给它(而不是构造函数参数),或者根本不使用 viewModel!
评论