Judul itu sendiri adalah masalah saya, setiap kali saya membuka MainActivity lalu menavigasi ke fragmen lain yang tersedia di menu hamburger/laci lalu tekan/geser kembali untuk kembali di layar utama (fragmen pertama) itu dibuat ulang. Apakah ada komponen Nav untuk membuatnya tidak membuat ulang fragmen pertama? Saya menggunakan templat Navigasi Jetpack yang dihasilkan oleh Android Studio dan sepertinya itu adalah perilaku default.

Ini adalah Aktivitas Utama

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration
    private var _binding: ActivityMainBinding? = null

    // This property is only valid between onCreate and
    // onDestroyView.
    private val binding get() = _binding!!

    private lateinit var drawerLayout: DrawerLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        _binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setSupportActionBar(binding.appBarMain.toolbar)

        drawerLayout = binding.drawerLayout
        val navView: NavigationView = binding.navView
        val navController = findNavController(R.id.nav_host_fragment_content_main)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_home, R.id.nav_marketcap, R.id.nav_about), drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)

    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.main, menu)
        menu.findItem(R.id.action_settings).isChecked = AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES
        return true
    }


    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment_content_main)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }

    override fun onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.START))
            drawerLayout.closeDrawer(GravityCompat.START)
        else
            super.onBackPressed()
    }

}

Ini adalah Home Fragment (Fragmen pertama di MainActivity) yang menyimpan fragmen anak AssetFragment

class HomeFragment : Fragment() {

    private val homeViewModel: HomeViewModel by activityViewModels()
    private var _binding: FragmentHomeBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    private lateinit var viewPager : ViewPager2

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View {

        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val root: View = binding.root

        viewPager = binding.viewPagerContainer
        val bottomNav = binding.bottomNav
//        val tabLayout = binding.tabLayout

        val fragmentList : MutableList<Pair<String, Fragment>> = mutableListOf()
        fragmentList.add(Pair(getString(R.string.assets), AssetFragment.newInstance()))
        fragmentList.add(Pair(getString(R.string.news), NewsFragment.newInstance()))
        fragmentList.add(Pair(getString(R.string.videos), VideosFragment.newInstance()))

        val adapter = AppFragmentAdapter(fragmentList, this)

        viewPager.adapter = adapter
        viewPager.offscreenPageLimit = 2

        viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {

            override fun onPageSelected(position: Int) {
                super.onPageSelected(position)
                bottomNav.menu.getItem(position).isChecked = true
                homeViewModel.setTitle(adapter.getFragmentTabName(position))
            }

        })

        val bottomNavListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
            when(item.itemId) {
                R.id.page_1 -> {
                    // Respond to navigation item 1 click
                    viewPager.setCurrentItem(0, true)
                    true
                }
                R.id.page_2 -> {
                    // Respond to navigation item 2 click
                    viewPager.setCurrentItem(1, true)
                    true
                }
                R.id.page_3 -> {
                    // Respond to navigation item 3 click
                    viewPager.setCurrentItem(2, true)
                    true
                }
                else -> false
            }
        }

        bottomNav.setOnNavigationItemSelectedListener(bottomNavListener)

//        val layoutInflater : LayoutInflater = LayoutInflater.from(context)
        //Connect TabLayout with ViewPager2
//        TabLayoutMediator(tabLayout, viewPager){ tab, position ->
//            tab.customView = prepareTabView(layoutInflater, tabLayout, adapter.getFragmentTabName(position), tabIcons[position])
//        }.attach()

        return root
    }

//    private fun prepareTabView(
//        layoutInflater: LayoutInflater,
//        tabLayout: TabLayout,
//        fragmentName: String,
//        drawableId: Int
//    ): View {
//
//        val rootView : View = layoutInflater.inflate(R.layout.main_custom_tab_text, tabLayout, false)
//
//        val tabName : AppCompatTextView = rootView.findViewById(R.id.tabName)
//
//        tabName.text = fragmentName
//        tabName.setCompoundDrawablesWithIntrinsicBounds(null, AppCompatResources.getDrawable(requireContext(), drawableId), null, null)
//
//        return tabName
//
//    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onResume() {
        super.onResume()

        requireView().isFocusableInTouchMode = true
        requireView().requestFocus()
        requireView().setOnKeyListener(object : View.OnKeyListener {

            override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {
                if (event!!.action == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                    onBackPress()
                    return true
                }
                return false
            }

        })
    }

    fun onBackPress() {

        if (viewPager.currentItem != 0)
            viewPager.setCurrentItem(0, true)
        else
            requireActivity().onBackPressed()

    }
}

Ini adalah salah satu fragmen anak yang ditampilkan di ViewPager yang dihosting oleh fragmen induk HomeFragment

class AssetFragment : Fragment() {

    companion object {
        fun newInstance() = AssetFragment()
    }

    private lateinit var viewModel: AssetViewModel

    private var _binding: FragmentAssetsBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    private lateinit var logTxt: AppCompatTextView
    private lateinit var recyclerView: RecyclerView
    private lateinit var swipeRefreshLayout: SwipeRefreshLayout

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {

        _binding = FragmentAssetsBinding.inflate(inflater, container, false)
        val root: View = binding.root

        recyclerView = binding.recyclerView
        swipeRefreshLayout = binding.refreshLayout
        logTxt = binding.errorLog

        recyclerView.layoutManager = LinearLayoutManager(context)
        adapter = AssetAdapter(requireContext(), this)
        recyclerView.adapter = adapter

        swipeRefreshLayout.isRefreshing = true
        fetchAssets("30")

        swipeRefreshLayout.setOnRefreshListener {
            swipeRefreshLayout.isRefreshing = true
            fetchAssets("30")
        }

        return root

    }

    private fun fetchAssets(limit: String) {

        //Network stuff
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        viewModel = ViewModelProvider(this).get(AssetViewModel::class.java)
        // TODO: Use the ViewModel
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

}

Navigasi xml

Ini adalah fragmen yang akan ditampilkan di menu laci

    <?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@+id/nav_home">

<fragment
    android:id="@+id/nav_home"
    android:name="com.myapp.ui.home.HomeFragment"
    android:label="@string/home"
    tools:layout="@layout/fragment_home" />

<fragment
    android:id="@+id/nav_marketcap"
    android:name="com.myapp.ui.marketcap.MarketCapFragment"
    android:label="@string/marketCap"
    tools:layout="@layout/fragment_marketcap" />

<fragment
    android:id="@+id/nav_about"
    android:name="com.myapp.ui.about.AboutFragment"
    android:label="@string/about"
    tools:layout="@layout/fragment_about" />

</navigation>

Menu.xml

 <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">

    <item android:title="@string/menu">
        <menu>

            <item
                android:id="@+id/nav_home"
                android:icon="@drawable/ic_assets"
                android:title="@string/home" />

            <item
                android:id="@+id/nav_marketcap"
                android:icon="@drawable/ic_marketcap"
                android:title="@string/marketCap" />

            <item
                android:id="@+id/nav_about"
                android:icon="@drawable/ic_about"
                android:title="@string/about" />

        </menu>
    </item>

</group>



     <item android:title="@string/connect">
            <menu>
                <item
                    android:id="@+id/email_connect"
                    android:icon="@drawable/ic_email"
                    android:title="@string/fui_email_hint" />
            </menu>
        </item>

</menu>

Mengalir:

Buka aplikasi

Meluncurkan MainActivity

Tampilkan HomeFragment (AssetFragment)

Buka menu laci

Pilih item mis. Tentang (Tentang Fragmen)

Tekan/Gesek kembali

Masalah di sini HomeFragment onCreateView dipicu sekali lagi

Perilaku yang diharapkan HomeFragment tidak perlu lagi memperbesar tampilan karena kami benar-benar membuat pengguna kembali ke tujuan pertama. Kecuali jika pengguna itu sendiri menekan item Home di menu laci kami, itulah saat HomeFragment akan dibuat ulang.

1
Undefined function 23 April 2021, 06:14

1 menjawab

Jawaban Terbaik

Sesuai Menyimpan status dengan panduan fragmen, diharapkan tampilan Fragmen Anda (tetapi bukan fragmen itu sendiri) dihancurkan dan dibuat ulang saat berada di tumpukan belakang.

Sesuai panduan itu, salah satu jenis status adalah status non-konfigurasi:

NonConfig: data yang diambil dari sumber eksternal, seperti server atau repositori lokal, atau data yang dibuat pengguna yang dikirim ke server setelah di-commit.

Data NonConfig harus ditempatkan di luar fragmen Anda, seperti di ViewModel. Kelas ViewModel secara inheren memungkinkan data bertahan dari perubahan konfigurasi, seperti rotasi layar, dan tetap berada di memori saat fragmen ditempatkan di back-stack.

Jadi fragmen Anda seharusnya tidak pernah memanggil fetchAssets("30") di onCreateView(). Alih-alih, logika ini harus terjadi di dalam ViewModel sehingga langsung tersedia saat fragmen kembali dari back-stack. Sesuai panduan ViewModel, fetchAssets Anda harus dilakukan di dalam ViewModel dan Fragmen Anda akan mengamati data itu.

1
ianhanniballake 23 April 2021, 04:30