Fragments destroyed / recreated with Jetpack's Android Navigation components

蹲街弑〆低调 提交于 2019-11-27 00:55:29

问题


I'm trying to implement Navigation with Jetpack's architecture components in my existing app.

I have a single activity app where the main fragment (ListFragment) is a list of items. Currently, when the user taps on a list item a second fragment is added to the stack by fragmentTransaction.add(R.id.main, detailFragment). So when back is pressed the DetailFragment is detached and the ListFragment is shown again.

With Navigation architecture this is handled automatically. Instead of adding the new fragment it's replaced, so the fragment view is destroyed, onDestroyView() is called and onCreateView() is called when back is pressed to recreate the view.

I understand that this is a good pattern used with LiveData and ViewModel to avoid using more memory than necessary, but in my case this is annoying because the list has a complex layout and inflating it is time and CPU consuming, also because I'll need to save the scroll position of the list and scroll again to the same position user left the fragment. It's possible but seems it should exists a better way.

I've tried to "save" the view in a private field on fragment and re-use it on onCreateView() if is already there, but it seems an anti-pattern.

private View view = null;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    if (view == null) {
        view = inflater.inflate(R.layout.fragment_list, container, false);
        //...
    }

    return view;
}

Is there any other, more elegant, way to avoid re-inflating the layout?


回答1:


Ian Lake from google replied me that we can store the view in a variable and instead of inflating a new layout, just return the instance of pre-stored view on onCreateView()

Leakcanery may show this as leak but its false positive..




回答2:


I tried like this, and it works for me.

  • Init ViewModel by navGraphViewModels (Live on Navigation scope)
  • Store any to-restore state in ViewModel
// fragment.kt
private val vm by navGraphViewModels<VM>(R.id.nav_graph) { vmFactory }

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // Restore state
    vm.state?.let {
        (recycler.layoutManager as GridLayoutManager).onRestoreInstanceState(it)
    }
}

override fun onPause() {
    super.onPause()
    // Store state
    vm.state = (recycler.layoutManager as GridLayoutManager).onSaveInstanceState()
}

// vm.kt
var state:Parcelable? = null



回答3:


You can have a persistent view for your fragment through below implementation

BaseFragment

open class BaseFragment : Fragment(){

        var hasInitializedRootView = false
        private var rootView: View? = null

        fun getPersistentView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?, layout: Int): View? {
            if (rootView == null) {
                // Inflate the layout for this fragment
                rootView = inflater?.inflate(layout,container,false)
            } else {
                // Do not inflate the layout again.
                // The returned View of onCreateView will be added into the fragment.
                // However it is not allowed to be added twice even if the parent is same.
                // So we must remove rootView from the existing parent view group
                // (it will be added back).
                (rootView?.getParent() as? ViewGroup)?.removeView(rootView)
            }

            return rootView
        }
    }

MainFragment

class MainFragment : BaseFragment() {


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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        if (!hasInitializedRootView) {
            hasInitializedRootView = true
            setListeners()
            loadViews()
        }
    }
}

Source



来源:https://stackoverflow.com/questions/54581071/fragments-destroyed-recreated-with-jetpacks-android-navigation-components

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!