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日

相关文章

  • PHP服务端SESSION管理工具提供下载

    以下是PHP服务端SESSION管理工具的下载攻略: 1. 目标 我们的目标是通过下载一个PHP服务端SESSION管理工具,实现对用户SESSION的管理。对于初学者而言,SESSION管理是一个非常重要的部分,它可以让你更好的管理用户状态,提高网站的安全性。 2. 准备 在下载PHP服务端SESSION管理工具之前,需要有以下准备: 一台安装了PHP的服…

    other 2023年6月27日
    00
  • 漫游配置文件和本地配置文件有啥区别? Win11快速禁用漫游配置文件的技巧

    当我们在使用 Microsoft 帐户登录到 Windows 11 时,默认情况下会开启“漫游用户个人设置(Roaming user profiles)”功能。这个功能会将用户的个人设置和文件自动上传到 Microsoft 云端,同时也可以在不同的设备上同步用户的设置和文件。这就是漫游配置文件。 与之相对应的是本地配置文件,也就是不与任何云服务同步的用户配置…

    other 2023年6月25日
    00
  • 合金装备5幻痛双足兵器开发位置及获得方法

    合金装备5幻痛双足兵器开发位置及获得方法攻略 在《合金装备5幻痛》中,双足兵器是一种强大的装备,可以提供额外的火力和机动性。本攻略将详细介绍双足兵器的开发位置和获得方法。 开发位置 双足兵器的开发位置分布在游戏的不同地点,以下是两个示例: 示例1:Nova Braga Airport Nova Braga Airport是一个位于非洲的地点,你可以在这里找到…

    other 2023年7月27日
    00
  • qt之qtscript

    Qt之QtScript QtScript是Qt框架中的一个模块,它提供了一种脚本语言,可以在Qt应用程序中使用JavaScript脚本。本攻略将详细介绍QtScript的使用方法,包括基本概、安装配置和示例说明。 基本概念 QtScript是Qt框架中的一个模块,它提供了一种脚语言,可以在Qt应用程序中使用JavaScript脚本。在QtScript,我们可…

    other 2023年5月6日
    00
  • 正则完全匹配某个字符串

    下面是关于如何使用正则表达式进行完全匹配某个字符串的完整攻略,包含两个示例说明。 什么是正则表达式? 正则表达式是一种用于匹配字符串的模式。它可以用来检查一个字符串是否符合某种模式,或者从一个字符串中提取出符合某种模式的子串。 如何使用正则表达式进行完全匹配? 在正则表达式中,你可以使用 ^ 和 $ 符号来表示字符串的开头和结尾。如果你想要完全匹配一个字符串…

    other 2023年5月8日
    00
  • Ubuntu有望正式支持ZFS文件系统

    Ubuntu有望正式支持ZFS文件系统,这将使得存储管理变得更加易于管理和操控。下面详细讲解Ubuntu官方支持ZFS文件系统的完整攻略: 安装 ZFS 首先,我们需要安装ZFS文件系统。在Ubuntu中可以通过下面的命令来安装ZFS。 sudo apt-get install zfsutils-linux 创建并挂载ZFS文件系统 安装好ZFS之后,我们就…

    other 2023年6月27日
    00
  • IIS下配置页面重写(配合插件url-rewrite2去除页面后缀名)的实现方法

    IIS下配置页面重写(配合插件url-rewrite2去除页面后缀名)的实现方法 在IIS(Internet Information Services)中配置页面重写,可以使用插件url-rewrite2来去除页面的后缀名。下面是详细的攻略,包含了两个示例说明。 步骤一:安装url-rewrite2插件 下载url-rewrite2插件并安装到IIS服务器上…

    other 2023年8月6日
    00
  • 跟老齐学Python之编写类之一创建实例

    下面是“跟老齐学Python之编写类之一创建实例”的完整攻略。 创建实例 在Python中,类(class)是一种面向对象编程(OOP)的基本概念。类是一个抽象的概念,它代表着一类事物的共性特征,而实例(instance)则是类的具体实现。我们可以把类看做是一个模板,而实例就是用这个模板创建出来的实体。 创建类 在Python中,我们可以使用class关键字…

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