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

yizhihongxing

我来详细讲解一下“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日

相关文章

  • linux系统下hosts文件详解及配置

    下面就为您详细讲解 “Linux系统下hosts文件详解及配置”的完整攻略: 什么是hosts文件? hosts是一种用于指定域名到IP地址之间对应关系的计算机文件。当我们在浏览器中访问一个网站时,浏览器首先会查询hosts文件以获取网站对应的IP地址,然后再去访问这个IP地址。在Linux系统中,hosts文件的位置通常位于/etc/hosts。 host…

    other 2023年6月27日
    00
  • 开发 Internet Explorer 右键功能表(ContextMenu)

    开发 Internet Explorer 右键功能表(ContextMenu) 的完整攻略 Internet Explorer 是一款著名的浏览器,如何在 IE 中开发自定义的右键菜单呢?本文将介绍开发 Internet Explorer 右键功能表(ContextMenu) 的完整攻略。 准备工作 在开始开发之前,需要准备以下工作: 编写一个 JavaSc…

    other 2023年6月27日
    00
  • 苹果新编程语言Swift由克里斯·拉特纳耗时4年基本人开发完成

    苹果新编程语言Swift是一门比Objective-C更为现代的编程语言,由苹果公司推出并用于开发iOS、macOS和watchOS等操作系统应用程序。Swift于2014年首次发布,被誉为iOS开发的未来。它克服了Objective-C语言的一些限制,使代码更易读、更安全、更易于维护。Swift的特点包括类型安全、自动内存管理、语言交互性、高效性以及相比于…

    other 2023年6月26日
    00
  • node.js+postman实现模拟HTTP服务器与客户端交互

    Node.js 是一种基于 Chrome V8 引擎的 JavaScript 运行时,使 JavaScript 可以在服务端运行,同时提供了丰富的模块库,可以用于快速搭建 Web 应用、命令行工具等。 Postman 是一个 API 测试工具,提供了丰富的功能,可以模拟客户端发起 HTTP 请求,方便开发人员进行接口测试和调试。 下面是使用 Node.js …

    other 2023年6月27日
    00
  • 解决Eclipse创建android项目无法正常预览布局文件问题的方法

    解决Eclipse创建android项目无法正常预览布局文件问题的方法攻略 问题描述 在使用Eclipse创建Android项目时,有时会遇到无法正常预览布局文件的问题。这可能导致无法准确地查看和编辑布局,给开发工作带来不便。 解决方法 以下是解决该问题的一些方法: 方法一:更新ADT插件 打开Eclipse,并导航到“Help”菜单。 选择“Eclipse…

    other 2023年8月21日
    00
  • PostgreSQL 查看服务器版本的三种方法

    PostgreSQL 查看服务器版本的三种方法 在 PostgreSQL 中,有多种方法可以查看服务器的版本信息。下面将介绍三种常用的方法。 方法一:使用 psql 命令行工具 打开终端或命令行窗口。 输入以下命令连接到 PostgreSQL 数据库: shell psql -U <username> -d <database_name&g…

    other 2023年8月3日
    00
  • 360压缩减少关联的右键菜单项方法图解

    下面是详细讲解如何在360压缩中减少关联的右键菜单项的完整攻略。 前置知识 在进行本攻略之前,需要你已经安装了360压缩,并且了解一些基本的文件压缩和解压缩操作。另外,本攻略的操作步骤可能会因不同版本的360压缩而有所不同,请以你所使用的版本为准。 1. 打开360压缩 双击桌面上的360压缩图标,或者通过开始菜单中的程序列表打开360压缩。 2. 进入设置…

    other 2023年6月27日
    00
  • 真正的获取客户端真实IP地址及利弊分析

    真正的获取客户端真实IP地址及利弊分析攻略 获取客户端真实IP地址对于网络应用程序来说是非常重要的,它可以用于识别用户、进行访问控制、统计分析等。然而,由于网络架构的复杂性和安全性的考虑,获取真实IP地址并不总是一件容易的事情。本攻略将详细介绍如何真正获取客户端真实IP地址,并分析其中的利弊。 1. 使用HTTP头字段 HTTP头字段中的X-Forwarde…

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