Android Navigation重建Fragment问题分析及解决

我来详细讲解一下“Android Navigation重建Fragment问题分析及解决”的完整攻略。

什么是Navigation重建Fragment问题?

在使用Android Navigation组件时,如果使用了NavigationUI.setupWithNavController()来设置BottomNavigationView或者使用了AppBarConfiguration来配置Toolbar,那么在导航到其他Fragment或者旋转屏幕等操作后回到之前的Fragment时,有时候会重建Fragment。这就导致了之前Fragment中的数据丢失,用户体验差等问题,这就是Navigation重建Fragment问题。

Navigation重建Fragment问题分析

为什么会导致Fragment重建?

当我们导航到一个Fragment时,它会被添加到回退栈中。当我们点击返回按钮或者调用NavController.popBackStack()方法时,会从回退栈中弹出当前Fragment并重新显示上一个Fragment。而当我们重新进入这个Fragment时,Fragment会尝试恢复之前未保存的UI状态。

然而,当我们使用NavigationUI.setupWithNavController()或者AppBarConfiguration来设置导航控制器时,会在活动的生命周期方法中调用不同的方法来保存和恢复导航控制器的状态,这会间接导致Fragment重建的问题。

Navigation重建Fragment的影响

  • 丢失未保存的数据;
  • 界面状态回到初始化状态;
  • 采用ViewPager2+Fragment方式会重新加载当前和相邻的Fragment。

Navigation重建Fragment问题解决

Navigation重建Fragment问题的解决方案可以分为两类。

方案一:禁用Navigation控制器

这是禁用Navigation控制器来解决Navigation重建Fragment问题的一种方案。需要在onCreate()中设置savedInstanceState为null,以便在屏幕旋转等配置更改时,不会自动恢复之前的Fragment。

override fun onCreate(savedInstanceState: Bundle?) {
    savedInstanceState = null
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
    val navController = findNavController(R.id.nav_host_fragment)
    NavigationUI.setupWithNavController(bottomNavigationView, navController)
}

方案二:子类化Fragment

重建问题的另一种解决方案是在Fragment中手动保存和恢复UI状态。这可以通过下面两种方式来实现:

1. 保存和恢复状态

在Fragment中创建一个成员变量,用于保存Fragment的状态:

private lateinit var state: Bundle

onSaveInstanceState()方法中将状态保存在Bundle实例中:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putBundle("my_state", state)
}

onCreateView()方法中恢复状态:

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    // Inflate the layout for this fragment
    if (savedInstanceState != null) {
        state = savedInstanceState.getBundle("my_state")
    }
    return inflater.inflate(R.layout.fragment_blank, container, false)
}

2. 阻止Fragment重建

重写Fragment中的onDestroyView()方法,并且在方法中调用retainInstance = true来阻止Fragment销毁并保留其UI状态:

override fun onDestroyView() {
    super.onDestroyView()
    retainInstance = true
}

示例一

下面是一个禁用Navigation控制器的示例。在MainActivity.kt中设置默认的NavController即可:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        savedInstanceState = null
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val navController = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)!!.findNavController()
        val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
        NavigationUI.setupWithNavController(bottomNavigationView, navController)
    }
}

示例二

现在我们来看一个更具体的示例,该示例中我们想在Fragment之间传递数据和保存UI状态。我们将创建一个具有EditText和Button的Fragment,以演示如何保存和恢复其内容。

1. 创建一个新的Kotlin文件,并实现想要添加保存状态和传递数据的Fragment。例如,你可以创建一个新的Fragment作为默认模板来完成这项工作。

class BlankFragment : Fragment() {

    private lateinit var editText: EditText
    private lateinit var inputText: String

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_blank, container, false)
        editText = view.findViewById(R.id.editText)
        val button = view.findViewById<Button>(R.id.button)
        button.setOnClickListener {
            inputText = editText.text.toString().trim()
            val action = BlankFragmentDirections.actionBlankFragmentToDisplayFragment(inputText)
            NavHostFragment.findNavController(this).navigate(action)
        }
        if (savedInstanceState != null) {
            inputText = savedInstanceState.getString("saved_text").toString()
            editText.setText(inputText)
        }
        return view
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putString("saved_text", editText.text.toString().trim())
    }
}

2. 使用NavOptions.Builder来为传递的数据创建新的Bundle对象。下面是DisplayFragment的完整代码演示:

class DisplayFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_display, container, false)

        val textView = view.findViewById<TextView>(R.id.textView)

        val args = DisplayFragmentArgs.fromBundle(requireArguments())
        val data = args.displayText

        textView.text = data

        return view
    }
}

现在,我们已经学会了如何解决Navigation重建Fragment问题并且通过示例演示了如何保存和恢复Fragment中的状态和传递数据。希望这篇文章对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android Navigation重建Fragment问题分析及解决 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • java如何使用fastjson修改多层嵌套的Objectjson数据

    Java使用Fastjson修改多层嵌套的Object JSON数据攻略 Fastjson是一个Java语言编写的高性能JSON处理器,它提供了一种简单而灵活的方式来处理JSON数据。下面是使用Fastjson修改多层嵌套的Object JSON数据的完整攻略。 步骤1:导入Fastjson库 首先,你需要在你的Java项目中导入Fastjson库。你可以通…

    other 2023年7月28日
    00
  • AngularJS中的按需加载ocLazyLoad示例

    AngularJS是一个流行的JavaScript框架,但是对于大型应用程序,为了提高性能,我们需要按需加载JavaScript文件。在AngularJS中,我们可以使用ocLazyLoad库来实现按需加载。在这里,我们将提供一个完整的攻略来讲解AngularJS中的按需加载ocLazyLoad示例。 需求分析 在介绍操作步骤之前,我们需要先分析一下我们的需…

    other 2023年6月25日
    00
  • uni-app跨域解决方案

    当你在使用uni-app开发跨平台应用时,可能会遇到跨域问题。下面是uni-app跨域解决方案的完整攻略: 在manifest.json文件中配置跨域 在manifest.json文件中,你可以使用”networkTimeout”和”debug”属性来配置跨域。下面是一个示例: json { “networkTimeout”: { “request”: 10…

    other 2023年5月8日
    00
  • ubuntu18.04使用docker部署gitlab并且使用自定义端口号

    以下是“ubuntu18.04使用docker部署gitlab并且使用自定义端口号”的完整攻略: ubuntu18.04使用docker部署gitlab并且使用自定义端口号 GitLab是一个基于Web的Git存储库工具,可以帮助团队作开发和管理代码。在本攻略中,我们将介绍如何使用Docker在Ubuntu 18.04上署GitLab,并使用自定义口号。 步…

    other 2023年5月7日
    00
  • MYSQL插入数据时检查字段值是否重复的方法详解

    下面是关于MYSQL插入数据时检查字段值是否重复的方法的详细攻略。 1. 简介 当我们向MySQL数据库表中插入数据时,由于某些原因,我们需要在插入数据之前检查一下某个字段值是否已经存在,如果存在就不再插入,否则执行插入操作。 2. 使用唯一索引 实现上述操作方法的一种有效方法就是使用唯一索引。 我们可以在需要进行检查的字段上创建唯一索引。这样插入数据时就可…

    other 2023年6月26日
    00
  • Android布局之绝对布局AbsoluteLayout详解

    那我来为你详细讲解“Android布局之绝对布局AbsoluteLayout详解”的完整攻略。 什么是绝对布局? 绝对布局(AbsoluteLayout)是Android中一种非常基础的布局,它可以让我们指定每个控件的具体位置,控件的位置取决于其左侧和顶部的偏移量。这种布局方式的好处是可以精确定位控件,使其按照我们的设计放置。但是,由于控件位置是绝对的,因此…

    other 2023年6月26日
    00
  • android.os.systemproperties在哪里?

    以下是关于“android.os.systemproperties在哪里?”的完整攻略,包括基本知识和两个示例。 基本知识 android.os.systemproperties是Android系统中一个类,用于获取和设置系统属性。系统属性是一些键值对,用于存储系统的一些配置信息,例如设备的型号、Android版本号等。android.os.systempr…

    other 2023年5月7日
    00
  • 全新Win11体验已发布,亚马逊应用商店预览版新增 1000 多个安卓 App,任务栏支持天气

    全新Win11体验已发布,亚马逊应用商店预览版新增 1000 多个安卓 App,任务栏支持天气 Win11体验全新升级 Windows 11 是全新一代 Windows 操作系统,由 Microsoft 公司于 2021 年 6 月 24 日首次发布,主打简洁、美观、高效等特点。Win11将为用户提供更加流畅、友好的操作体验、以及全新的用户界面。 下面我们来…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部