Содержание фрагмента исчезло, когда я вернулся к ним - PullRequest
3 голосов
/ 15 апреля 2019

Я использую компонент Навигация в приложении Single Activity для навигации, но у меня странное поведение с одним фрагментом.Это просто объяснить с помощью изображений.

У меня есть фрагмент с ViewPager.ViewPager содержит еще два фрагмента, поэтому кажется:

enter image description here

Bird - первый фрагмент, Тест -второй.Нижний элемент - Нижняя навигация , это , а не часть фрагмента.Фрагмент находится между панель инструментов и Нижняя навигация .

Этот фрагмент, содержащий ViewPager, не является начальным фрагментом, он находится где-то посередине стека.

Итак, когда пользователь нажимает на нижний пункт меню, запускается этот код навигации (от Основная активность ):

 bottom_navigation.apply {
            itemIconTintList = null
            setOnNavigationItemSelectedListener { item ->
                when (item.itemId) {
                    R.id.about_bottom -> {
                        findNavController(R.id.host).navigate(R.id.toAboutUs)
                    }
                    R.id.error_bottom -> {
                        findNavController(R.id.host).navigate(R.id.toMessage)
                    }
                }
                true
            }
        }

, где toMessage / toAboutUs являются глобальными точками другого фрагмента.

Так в чем проблема.Когда пользователь нажимает на нижний пункт меню, все работает хорошо.Но когда он нажал «назад», контент от фрагментов пропал.Это просто увидеть:

enter image description here

Я даже не могу предложить причину, если это.Я знаю, что «основной» фрагмент и фрагменты на ViewPager не воссоздают, так почему они теряют контент?

Я нигде не переопределяю поведение кнопки возврата.Я просто использую app:defaultNavHost="true" фрагмента хоста.


Как транспортируются данные: Когда пользователь нажимает кнопку, чтобы открыть Fragment с ViewPager, данные загружаются из DB и сохраняются только в ViewModelтогда пользователь будет перенесен в этот фрагмент.Когда оба дочерних фрагмента созданы, они загружают данные из ViewModel.И у меня нет места для кода, где я очищаю ViewModel, поэтому, когда пользователь нажимает назад, это на 100%, моя ViewModel содержит что-то.Но это не отображается.

UPD: Потратив некоторое время, я понимаю, что два «дочерних» фрагмента восстанавливаются не при возвращении назад, а в основном фрагменте.Я думаю, что проблема в этом, но все еще не понимаю, где именно.

Мне нужна ваша помощь, чтобы понять, что происходит.


Upd: предоставить некоторый код создания фрагментов. BaseCompatFragment расширяет Фрагмент

MainFragment (контейнер для двух других фрагментов):

class QuestionFragment : BaseCompatFragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_question, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        pager.adapter = QuestionViewPagerAdapter(fragmentManager!!)
        activity?.toolbar_title?.text = getString(R.string.title_question,1)

        layout_tab.apply {
            setupWithViewPager(pager)
            tabIconTint = null
            getTabAt(0)?.setIcon(R.drawable.ic_type_bird)
            getTabAt(1)?.setIcon(R.drawable.ic_hints)
        }
    }
}

QuestionViewPagerAdapter

    class QuestionViewPagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {

        override fun getItem(position: Int): BaseCompatFragment {
            when (position) {
                0 -> return HintsFragment()
                1 -> return BaseInfoFragment()
            }
            return HintsFragment()
        }

        override fun getCount(): Int {
            return 2
        }
    }

HintsFragment (птица)

class HintsFragment : BaseCompatFragment(), HintsFragmentContract.View {

    @Inject
    lateinit var presenter: HintsFragmentPresenter

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_hints, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        LibApp.get().injector.inject(this)
        presenter.attach(this)

        val animalWithHints =
            ViewModelProviders.of(activity!!).get(AnimalViewModel::class.java).getData().value

        val adapter = HintsAdapter(callback = { id ->
            //Some code will be here soon
        })
        //Do smth with content
        adapter.hintsList = animalWithHints?.animal?.hints?.split("///") as ArrayList<String>
        adapter.hintsStorage = animalWithHints.hints?.get(0) ?: Hints()

        recycler_hints.layoutManager = verticalManager(context)
        recycler_hints.adapter = adapter
    }
}

BaseInfoFragment (тест)

class BaseInfoFragment : BaseCompatFragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_base_info, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val animalWithHints =
            ViewModelProviders.of(activity!!).get(AnimalViewModel::class.java).getData().value

        //A lot of logic to hide/show content, don't think it can be intresting

        val isBaseInfoOpen = animalWithHints?.hints?.get(0)?.baseInfoOpened == 1
        setBlockLayoutState(!isBaseInfoOpen)

        if (isBaseInfoOpen) {
            openContent(animalWithHints)
        } else {
            text_base_info.text = getString(R.string.base_info_price, 100)
            btn_base_info_positive.setOnClickListener {
                if (btn_base_info_negative.visibility == View.GONE) {
                    btn_base_info_negative.visibility = View.VISIBLE
                    text_base_info.text = getString(R.string.default_doubts)
                } else {
                    openContent(animalWithHints)
                }
            }

            btn_base_info_negative.setOnClickListener {
                it.visibility = View.GONE
                text_base_info.text = getString(R.string.base_info_price, 100)
            }
        }
    }

    private fun getRareIcon(rare: Int, context: Context): Drawable {
        return when (rare) {
            1 -> ContextCompat.getDrawable(context, R.drawable.ic_rare_fine)!!
            2 -> ContextCompat.getDrawable(context, R.drawable.ic_rare_medium)!!
            3 -> ContextCompat.getDrawable(context, R.drawable.ic_rare_bad)!!
            else -> ContextCompat.getDrawable(context, R.drawable.ic_warning)!!
        }
    }

    private fun getRareText(rare: Int): String {
        return when (rare) {
            1 -> getString(R.string.base_info_rare_1)
            2 -> getString(R.string.base_info_rare_2)
            3 -> getString(R.string.base_info_rare_3)
            else -> getString(R.string.base_info_rare_4)
        }
    }

    private fun setBlockLayoutState(state: Boolean) {
        base_info_closer.visibility = when {
            state -> View.VISIBLE
            else -> View.GONE
        }
        base_info_content.visibility = when {
            state -> View.GONE
            else -> View.VISIBLE
        }
    }

    private fun openContent(animalWithHints: AnimalWithHints?) {
        (img_closed_base_info.drawable as Animatable).start()
        rare_img.setImageDrawable(getRareIcon(animalWithHints?.animal?.rare ?: 0, activity!!))
        rare_text.text = getRareText(animalWithHints?.animal?.rare ?: 0)
        setBlockLayoutState(false)
    }
}

Ответы [ 2 ]

2 голосов
/ 16 апреля 2019

Я думаю, проблема здесь: QuestionViewPagerAdapter(fragmentManager!!) Вам нужно использовать getFragmentManager() / getSupportFragmentManager(), когда вы добавляете фрагменты непосредственно в вашу деятельность.Но когда вам нужно добавить фрагмент к другому фрагменту, вам нужно использовать getChildFragmentManager().

Из getSupportFragmentManager() документации :

Вернуть FragmentManager длявзаимодействие с фрагментами, связанными с этим действием.

Таким образом, это причина, по которой ваша птица и фрагменты теста не воссоздали, когда их родительский фрагмент это сделал.

И из getChildFragmentManager() doc :

Возвращает приватный FragmentManager для размещения и управления фрагментами внутри этого фрагмента.

Это должно сработать.Надеюсь, поможет.

0 голосов
/ 15 апреля 2019

В onCreateView MainFragment попробуйте поставить if (! IsAdded ()) return;где-то.Я сталкивался с той же проблемой раньше, однако, ваш код немного отличается от моего.Что я сделал, так это положил, если (! IsAdded ()) вернул;.

...