Как уничтожаются фрагменты, созданные с помощью фрагментовtateadapter (viewpager2) - PullRequest
1 голос
/ 22 января 2020

В состоянии c (3 страницы) в настройке ViewPager2, где ViewPager2 находится во фрагменте, я создал 3 фрагмента в потомке FragmentStateAdapter. Я даже собрал фрагменты в таблице (MutableList<Fragment> = Vector<Fragment>()) в этом потомке для дальнейшего использования. offscreenPageLimit установлен на 3, поэтому фрагменты не будут d ie, а будут только возобновлены и приостановлены.

Один фрагмент представляет собой карту, один фрагмент представляет собой таблицу настроек с несколькими ссылками на жилые данные ( на основе помещения), третьим будет страница с изображением.

При выходе из этого фрагмента ViewPager2 и повторной обработке базы данных помещения (обновление содержимого) мое приложение не работает ... мне пришло в голову, что три фрагмента, созданные в Потомок FragmentStateAdapter не был уничтожен (конечно?) (Обнуленная база данных не может быть обработана фрагментом), потому что FragmentStateAdapter никак не мог уничтожить эти фрагменты. Конечно, я мог бы убить их в потомке FragmentStateAdapter, но разве нет простого способа справиться с этими смертями?

Большая часть кода ниже основана на шаблонах, поэтому некоторые могут быть излишними

Извлечение кода:

AddStationFragment:

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() для AddStationFragment я проверил childFragmentManager, но там нет никаких фрагментов (как и следовало ожидать, поскольку я предоставил fragmentActivity в вызове FragmentStateAdapterFragmentStateAdapter потомок AddStationFragmentStateAdapter), где они сидят и кто (и как) должен (я) уничтожить их наилучшим образом?

RG

Ответы [ 2 ]

1 голос
/ 22 января 2020

Я на самом деле нашел ответ на свой вопрос, не напрямую, а обходной путь, который может помочь другим тоже с такой же проблемой.

A. В FragmentStateAdapter по убыванию (т.е. AddStationFragmentStateAdapter) измените «искусственный» fragmentList на public, чтобы вы могли добраться до него снаружи.

B. затем в методе onDestroy() фрагмента ViewPager2 (т.е. AddStationFragment) выполните итерацию по publi c fragmentList, и вызов fragment.parentFragmentManager.beginTransaction().remove(fragment).commit()

«B» освободит фрагмент из список, в котором он находится, и все аккуратно и чисто ...

изменения кода:


В AddStationFragmentStateAdapter мы устанавливаем публикуемый фрагментList c:

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

0 голосов
/ 24 февраля 2020

Вместо передачи activity в конструктор FragmentStateAdapter вы должны передать родительский Fragment.

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

Когда родительский фрагмент будет уничтожен, фрагменты окна просмотра также будут уничтожены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...