Android Fragment 在按下后退按钮时未保存 UI 状态
Posted
技术标签:
【中文标题】Android Fragment 在按下后退按钮时未保存 UI 状态【英文标题】:Android Fragment not saving UI State on pressing Back Button 【发布时间】:2021-09-18 12:15:32 【问题描述】:我的用例遇到了问题。它非常基本的用例。我有一个主要活动和 2 个片段。主要活动没有太多的用户界面。它所做的只是用 FirstFragment 替换它的容器。
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null)
supportFragmentManager.beginTransaction()
.replace(R.id.container, FirstFragment.newInstance())
.addToBackStack(null)
.commit()
FirstFragment 有 2 个按钮 - initializeButton 和 button1,其中 initializeButton 默认处于启用状态,而 button1 仅在按下 initializeButton 后启用。 在 initializeButton 之后按下 Button1 后,它将启动 SecondFragment。以下是执行此操作的代码。
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.container, SecondFragment.newInstance())
.addToBackStack(null)
.commit()
现在,这会正确启动 Secondfragment。现在,当我在 Fragment2 中按下后退按钮时,我想要的行为是第一个片段在两个按钮都处于启用状态时启动。相反,它将进入第一个片段中的默认状态(初始化按钮处于启用状态,而按钮 1 处于禁用状态)。感谢任何反馈。谢谢
主活动
class MainActivity : AppCompatActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState == null)
supportFragmentManager.beginTransaction()
.replace(R.id.container, FirstFragment.newInstance())
.addToBackStack(null)
.commit()
MainActivity 布局
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_
android:layout_
tools:context=".MainActivity" />
第一个片段
class FirstFragment : Fragment()
companion object
fun newInstance() = FirstFragment()
private lateinit var viewModel: SharedViewModel
private lateinit var initializeButton: Button
private lateinit var button1: Button
private lateinit var newview: View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View?
if (savedInstanceState == null)
newview = inflater.inflate(R.layout.fragment_first, container, false)
return newview
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
super.onViewCreated(view, savedInstanceState)
initializeButton = view.findViewById(R.id.button1)
initializeButton.setOnClickListener
button1.isEnabled = true
button1 = view.findViewById(R.id.button2)
button1.setOnClickListener
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.container, SecondFragment.newInstance())
.addToBackStack(null)
.commit()
override fun onSaveInstanceState(outState: Bundle)
super.onSaveInstanceState(outState)
outState.putBoolean("initState", initializeButton.isEnabled)
outState.putBoolean("button1State", button1.isEnabled)
override fun onViewStateRestored(savedInstanceState: Bundle?)
super.onViewStateRestored(savedInstanceState)
if (savedInstanceState != null)
initializeButton.isEnabled = savedInstanceState.getBoolean("initState")
button1.isEnabled = savedInstanceState.getBoolean("button1State")
片段优先布局
<LinearLayout 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:layout_
android:layout_
tools:context=".FirstFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_
android:layout_>
<Button
android:id="@+id/button1"
android:layout_
android:layout_
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/initialize"
android:enabled="true"
android:layout_marginTop="5dp"/>
<Button
android:id="@+id/button2"
android:layout_
android:layout_
app:layout_constraintTop_toBottomOf="@id/button1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@string/button2"
android:enabled="false"
android:layout_marginTop="5dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
第二个片段
class SecondFragment : Fragment()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View?
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false)
companion object
fun newInstance() = SecondFragment()
二次碎片布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical">
<TextView
android:id="@+id/info"
android:layout_
android:layout_
android:gravity="center"
android:text="@string/second_fragment"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textStyle="bold"
android:visibility="visible"/>
<ListView
android:id="@+id/listView"
android:layout_
android:layout_ />
</LinearLayout>
【问题讨论】:
您是否尝试保存 onPause 状态? 【参考方案1】:您更换片段有什么特别的原因吗?如果没有,您可以简单地添加它而不是替换它,这将确保状态得到维护。
你的代码会这样改变
.add(R.id.container, SecondFragment.newInstance())
.addToBackStack(null)
.commit()
【讨论】:
添加会覆盖第一个片段。我想移动到新屏幕 @KSP 它将重叠,但如果您具有适当的 XML 属性,即背景颜色,则顶部的片段将优先,可单击为真,可聚焦为真。休息一下,如果您在onViewStateRestored
中获得正确的数据,我建议您检查和调试一次。
.add(R.id.container, SecondFragment.newInstance()) .hide(this) .addToBackStack(null) .commit() - 所以上面的改变对我的用例有用。只是当我按下后退按钮时,它会删除第二个片段。
@KSP 如果它对您有用,您可以将其标记为正确答案以供其他人参考。以上是关于Android Fragment 在按下后退按钮时未保存 UI 状态的主要内容,如果未能解决你的问题,请参考以下文章