1

在 ViewPager2 位于片段中的静态(3 页)ViewPager2 设置中,我在 FragmentStateAdapter 后代中创建了 3 个片段。我什至MutableList<Fragment> = Vector<Fragment>()在该后代的表 ( ) 中收集了片段以供以后参考。offscreenPageLimit设置为,因此3片段不会消亡,而只会恢复和暂停。

一个片段是地图,一个片段是具有多个实时数据引用(基于房间)的表格设置,第三个将是图片页面。

当离开这个 ViewPager2 片段并回收房间数据库(刷新内容)时,我的应用程序崩溃了......我突然想到在 FragmentStateAdapter 后代中创建的三个片段没有被破坏(当然?)(一个空数据库不能由片段处理),因为 FragmentStateAdapter 无法杀死这些片段。当然我可以在 FragmentStateAdapter 后代中杀死它们,但是没有任何简单的方法来处理这些死亡吗?

下面的大部分代码都是基于模板的,所以有些可能是不必要的

代码摘录:

添加站片段:

class AddStationFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
private var listener: OnFragmentInteractionListener? = null

private val TAG by lazy { this::class.java.simpleName }

private lateinit var adRequest: AdRequest

private lateinit var binding: FragmentAddStationBinding

private lateinit var viewModel: AddStationViewModel

var fragments: MutableList<Fragment> = Vector<Fragment>()

lateinit var addStationFragmentStateAdapter: AddStationFragmentStateAdapter

override fun onCreate(savedInstanceState: Bundle?) {
    Log.i(TAG,"fra: onCreate()")
    super.onCreate(savedInstanceState)
    arguments?.let {
        param1 = it.getString(ARG_PARAM1)
        param2 = it.getString(ARG_PARAM2)
    }
}

override fun onResume() {
    Log.i(TAG,"fra: onResume()")
    super.onResume()

    activity?.let {activity->
        activity.fab?.let { fab ->
            fab.hide()
            fab.setImageDrawable(resources.getDrawable(R.drawable.ic_baseline_check_24, context?.theme))
            fab.clearAnimation()
            //fab.isEnabled = false

            fab.setOnClickListener { view ->
                Log.i(TAG,"fab.clicked !")
            }

            //fab.show()
        }

        (activity as MainActivity).setOptionsMenu(OptionsMenuSet.ADDSTATION)
        activity.bottom_navigation.visibility=View.GONE

        listener?.registerFragment(this)
    }

}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

    Log.i(TAG,"fra: onViewCreated")

    val tabtext = arrayOf(
        "Location",
        "Address",
        "Enterprise")

    val iconresource = arrayOf(
        R.drawable.ic_add_location_black_24dp,
        R.drawable.ic_info_outline_black_24dp,
        R.drawable.ic_baseline_business_24)

    TabLayoutMediator(
        binding.addStationTabLayout,
        binding.addStationViewPager2,
        TabLayoutMediator.TabConfigurationStrategy { tab: TabLayout.Tab, position: Int ->
            tab.text = tabtext[position]
            tab.setIcon(iconresource[position])
            tab.icon?.let { icon ->
                DrawableCompat.setTint(
                    icon,
                    ContextCompat.getColor(activity as Context, R.color.cardBG_lightred))
            }
            /*tab.icon?.setColorFilter(
                ContextCompat.getColor(activity as Context, R.color.cardBG_lightred),
                PorterDuff.Mode.SRC_IN)*/ //Deprecated


        }
    ).attach()



    //super.onViewCreated(view, savedInstanceState)
}

override fun onDestroy() {
    Log.i(TAG,"fra: onDestroy()")

    Log.i(TAG,"fra: Childfragment size: ${childFragmentManager.fragments.size}")



    super.onDestroy()
}


override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    Log.i(TAG,"fra: onCreateView()")

    binding = FragmentAddStationBinding.inflate(inflater, container, false)

    context?:return binding.root

    adRequest = AdRequest.Builder().build()

    binding.addStationAdView.loadAd(adRequest)

    addStationFragmentStateAdapter = AddStationFragmentStateAdapter(
        activity?:return binding.root,fragments)

    binding.addStationViewPager2.offscreenPageLimit = 3
    binding.addStationViewPager2.adapter = addStationFragmentStateAdapter

    val factory = InjectorUtils.provideAddStationViewModelFactory(context?:return binding.root)
    viewModel = ViewModelProvider(this, factory).get(AddStationViewModel::class.java)

    viewModel.liveNewStationForUser.observe(viewLifecycleOwner, Observer { station ->
        Log.i(TAG,"onCreateView liveNewStationForUser station = $station")
    })

    AddStationRepository.createTemplate("")

    return binding.root
}

// TODO: Rename method, update argument and hook method into UI event
fun onButtonPressed(uri: Uri) {
    listener?.onFragmentInteraction(uri)
}

override fun onAttach(context: Context) {
    Log.i(TAG,"fra: onAttach()")
    super.onAttach(context)
    if (context is OnFragmentInteractionListener) {
        listener = context
    } else {
        throw RuntimeException(context.toString() + " must implement OnFragmentInteractionListener")
    }
}

override fun onPause() {
    Log.i(TAG,"fra: onPause()")
    super.onPause()
}

override fun onDetach() {
    Log.i(TAG,"fra: onDetach()")
    super.onDetach()
    listener = null
}

/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 *
 *
 * See the Android Training lesson [Communicating with Other Fragments]
 * (http://developer.android.com/training/basics/fragments/communicating.html)
 * for more information.
 */
interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    fun onFragmentInteraction(uri: Uri)
    fun registerFragment(fragment: Fragment)
    fun unregisterFragment(fragment: Fragment)
}

companion object {
    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @param param2 Parameter 2.
     * @return A new instance of fragment AddStationFragment.
     */
    // TODO: Rename and change types and number of parameters
    @JvmStatic
    fun newInstance(param1: String, param2: String) =
        AddStationFragment().apply {
            arguments = Bundle().apply {
                putString(ARG_PARAM1, param1)
                putString(ARG_PARAM2, param2)
            }
        }
}
}

AddStationFragmentStateAdapter:(FragmentStateAdapter 的后代)

class AddStationFragmentStateAdapter(
fragmentActivity: FragmentActivity,
private val fragmentList: MutableList<Fragment>
) :
FragmentStateAdapter(fragmentActivity) {

private val TAG by lazy {this::class.java.simpleName}

override fun createFragment(position: Int): Fragment {

    Log.i(TAG, "createFragment position = $position")

    val fragment: Fragment = when (position) {
        0 -> FragmentAddStationMap()
        1 -> FragmentAddStationInfo()
        else -> FragmentAddStationEnterprise()
    }

    if (fragmentList.size <= position)
        fragmentList.add(fragment)
    else
        fragmentList[position] = fragment

    Log.i(TAG, "fra: fragmentList.size = ${fragmentList.size}")

    return fragment
}



override fun getItemCount(): Int {
    Log.i(TAG,"fra: fragmentListSize = ${fragmentList.size}")
    return 3
}

}

所以......你的建议是什么,我应该在onDestroy()for the他们坐下,谁(以及如何)应该(我)以最好的方式摧毁他们?AddStationFragmentchildFragmentManagerfragmentActivityFragmentStateAdapterFragmentStateAdapterAddStationFragmentStateAdapter

RG

4

2 回答 2

3

而不是将 传递activityFragmentStateAdapter的构造函数,您应该传递父级Fragment

class MainPagerAdapter(fragment: MyParentFragment) : FragmentStateAdapter(fragment) {}

当父片段被销毁时,viewpager 的片段也将被销毁。

于 2020-02-24T18:00:11.367 回答
1

实际上,我不是直接找到了我的问题的答案,而是找到了一种解决方法,它也可以帮助其他人解决同样的问题。

A. 在FragmentStateAdapterdescendandt (ie AddStationFragmentStateAdapter) 中将“人工”fragmentList改为public,这样您就可以从外面拿到它。

B.然后在'sfragment(ie )的onDestroy()方法中遍历public并调用ViewPager2AddStationFragmentfragmentListfragment.parentFragmentManager.beginTransaction().remove(fragment).commit()

“B”会从它所在的列表中释放片段,一切都变得整洁干净……

代码更改:


在 AddStationFragmentStateAdapter 中,我们将 fragmentList 设置为 public:

class AddStationFragmentStateAdapter(
 fragmentActivity: FragmentActivity,
 public var fragmentList: MutableList<Fragment>  //changed to public
) :
FragmentStateAdapter(fragmentActivity) {

private val TAG by lazy {this::class.java.simpleName}
...

并在 AddStationFragment onDestroy() 中:

override fun onDestroy() {
    Log.i(TAG,"fra: onDestroy()")

    Log.i(TAG,"fra: Childfragment size: ${childFragmentManager.fragments.size}")

    Log.i(TAG,"fra: addStationFragmentStateAdapter.fragmentList.size = ${addStationFragmentStateAdapter.fragmentList.size}")

    addStationFragmentStateAdapter.fragmentList.forEach { fragment:Fragment ->
        fragment.parentFragmentManager.beginTransaction().remove(fragment).commit()
    }

    super.onDestroy()
}

RG

于 2020-01-22T15:07:51.383 回答