Android ViewPager2+Fragment viewModelScope问题
Android ViewPager2+Fragment viewModelScope问题
·
Android ViewPager2+Fragment viewModelScope问题
核心代码
class MainActivity : AppCompatActivity() {
private lateinit var tabLayout: TabLayout
private lateinit var viewPager2: ViewPager2
private val titles = mutableListOf<String>()
private val fragments = mutableListOf<MyFragment>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tabLayout = findViewById(R.id.tab_layout)
viewPager2 = findViewById(R.id.view_pager2)
for (i in 'A'..'F') {
titles.add(i.toString())
fragments.add(MyFragment.newInstance(i.toString()))
}
viewPager2.adapter = MyAdapter(this, fragments)
viewPager2.offscreenPageLimit = 1
TabLayoutMediator(
tabLayout,
viewPager2,
object : TabLayoutMediator.TabConfigurationStrategy {
override fun onConfigureTab(
tab: TabLayout.Tab,
position: Int
) {
tab.text = titles[position]
}
}).attach()
}
class MyAdapter(fragmentActivity: FragmentActivity, val fragments: List<MyFragment>) :
FragmentStateAdapter(fragmentActivity) {
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
override fun getItemCount(): Int {
return fragments.size
}
}
}
class MyFragment : Fragment() {
private val viewModel: MyFragmentViewModel by viewModels()
private var title = ""
companion object {
fun newInstance(title: String) =
MyFragment().apply {
arguments = Bundle().apply {
putString("title", title)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
title = it.getString("title") ?: ""
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
Log.e("TAG", "Fragment ${title} 创建")
return inflater.inflate(R.layout.fragment_my, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val textView = view.findViewById<TextView>(R.id.text_view)
textView.text = "Fragment $title"
viewModel.load(title)
}
override fun onDestroyView() {
super.onDestroyView()
Log.e("TAG", "Fragment ${title} 销毁")
}
}
class MyFragmentViewModel : ViewModel() {
fun load(title: String) {
Log.e("TAG", "$title 开始加载")
Log.e("TAG", "$title viewModelScope是否可用:${viewModelScope.isActive}")
viewModelScope.launch {
delay(1000L)
Log.e("TAG", "$title 结束加载")
}
}
}
问题
首先点击 Fragment A,会执行 Fragment 的 ViewModel 的 load() 方法。接着点击 Fragment F,Fragment A 会被销毁掉,然后再点击 Fragment A,这时 Fragment A会被重新创建,而对应的 ViewModel 的 isActive 却是 false,导致 viewModelScope.launch 无法执行。
解决一
使用 Activity 的ViewModel。
class MyFragment : Fragment() {
private val viewModel: MyFragmentViewModel by activityViewModels()
}
解决二
使用 Fragment 中的 lifecycleScope。
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val textView = view.findViewById<TextView>(R.id.text_view)
textView.text = "Fragment $title"
viewModel.load(lifecycleScope, title)
}
}
解决三
不缓存实例,每次都重新创建 Fragment。
class MainActivity : AppCompatActivity() {
private val fragments = mutableListOf<() -> Fragment>()
override fun onCreate(savedInstanceState: Bundle?) {
for (i in 'A'..'F') {
titles.add(i.toString())
fragments.add({ MyFragment.newInstance(i.toString()) })
}
}
class MyAdapter(fragmentActivity: FragmentActivity, val fragments: List<() -> Fragment>) :
FragmentStateAdapter(fragmentActivity) {
override fun createFragment(position: Int): Fragment {
return fragments[position].invoke()
}
override fun getItemCount(): Int {
return fragments.size
}
}
}
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)