弹出 Fragment 后,所有 Edittext 都被替换为相同的值
All Editexts be replace by same value after pop a Fragment
我有一个奇怪的问题,我有 2 个片段,在第一个片段中,我有一些自定义 EditText
,以及一个用第二个片段替换它的按钮 (addToBackStack
= true),然后,在第二个片段中,我尝试使用 popBackStack()
返回到第一个片段,问题发生了,所有自定义 EditText
具有相同的值。
下面是我的全部代码
第一个片段
class FirstFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_next.setOnClickListener {
val transaction = requireActivity().supportFragmentManager!!.beginTransaction()
.replace(R.id.contentFrame, SecondFragment(), "")
commitTransaction(transaction, true, -1)
}
}
}
第二个片段
class SecondFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_back.setOnClickListener {
requireActivity().supportFragmentManager.popBackStack()
}
}
}
fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.sogia.replacefragmentdemo.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<com.sogia.replacefragmentdemo.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/btn_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="next"
/>
</LinearLayout>
fragment_second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btn_back"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="back"
/>
</LinearLayout>
自定义视图
class CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
inflate(context, R.layout.layout_custom_view, this)
}
}
layout_custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<EditText
android:id="@+id/edt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="input something"
/>
</LinearLayout>
如有任何回应,我们将不胜感激。
你不是在添加到返回堆栈,而是在替换,试试这个打开第二个片段,这将保持 FirstFragment 的状态完整并在堆栈中
btn_next.setOnClickListener {
val transaction = requireActivity().supportFragmentManager!!.beginTransaction()
.add(R.id.contentFrame, SecondFragment(), "")
commitTransaction(transaction, true, -1)
}
此外,您的两个 EditText
具有相同的 ID android:id="@+id/edt"
,因此运行 findViewById
的合成器函数将指向 EditText
[=15] 的同一对象=]
我会尝试为布局中的每个自定义视图添加不同的 ID。喜欢:
com.sogia.replacefragmentdemo.CustomView
android:id="@+id/custom1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
com.sogia.replacefragmentdemo.CustomView
android:id="@+id/custom2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
拥有相同的 ID 可能是个问题,因为管理状态可能会变得混乱。
检查这个解决方案:
终于找到了根本原因和解决办法,
感谢@abhradeep ghosh、@Eselfar、@MadScientist 和其他回复此消息的人 post。
原因:视图 ID 应该是唯一的!否则,您的状态将被具有相同 ID 的另一个视图覆盖。在我的例子中,我有 2 个 id 为 @id/edt
的视图,所以我的状态容器只包含它的 1 个实例——以状态存储过程中最后出现的那个为准。
这是我的解决方案,(来自 this post),
首先,为视图
的保存状态创建新的class
class SavedState(superState: Parcelable) : View.BaseSavedState(superState) {
var childrenStates: SparseArray<Any>? = null
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
childrenStates?.let {
out.writeSparseArray(it)
}
}
}
在我的 CustomView
@Suppress("UNCHECKED_CAST")
public override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
val ss = SavedState(superState)
ss.childrenStates = SparseArray()
for (i in 0 until childCount) {
getChildAt(i).saveHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
}
return ss
}
@Suppress("UNCHECKED_CAST")
public override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.superState)
for (i in 0 until childCount) {
getChildAt(i).restoreHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
}
}
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
dispatchFreezeSelfOnly(container)
}
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
dispatchThawSelfOnly(container)
}
我有一个奇怪的问题,我有 2 个片段,在第一个片段中,我有一些自定义 EditText
,以及一个用第二个片段替换它的按钮 (addToBackStack
= true),然后,在第二个片段中,我尝试使用 popBackStack()
返回到第一个片段,问题发生了,所有自定义 EditText
具有相同的值。
下面是我的全部代码
第一个片段
class FirstFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_next.setOnClickListener {
val transaction = requireActivity().supportFragmentManager!!.beginTransaction()
.replace(R.id.contentFrame, SecondFragment(), "")
commitTransaction(transaction, true, -1)
}
}
}
第二个片段
class SecondFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_second, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_back.setOnClickListener {
requireActivity().supportFragmentManager.popBackStack()
}
}
}
fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.sogia.replacefragmentdemo.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<com.sogia.replacefragmentdemo.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/btn_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="next"
/>
</LinearLayout>
fragment_second.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btn_back"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="back"
/>
</LinearLayout>
自定义视图
class CustomView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
init {
inflate(context, R.layout.layout_custom_view, this)
}
}
layout_custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<EditText
android:id="@+id/edt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="input something"
/>
</LinearLayout>
如有任何回应,我们将不胜感激。
你不是在添加到返回堆栈,而是在替换,试试这个打开第二个片段,这将保持 FirstFragment 的状态完整并在堆栈中
btn_next.setOnClickListener {
val transaction = requireActivity().supportFragmentManager!!.beginTransaction()
.add(R.id.contentFrame, SecondFragment(), "")
commitTransaction(transaction, true, -1)
}
此外,您的两个 EditText
具有相同的 ID android:id="@+id/edt"
,因此运行 findViewById
的合成器函数将指向 EditText
[=15] 的同一对象=]
我会尝试为布局中的每个自定义视图添加不同的 ID。喜欢:
com.sogia.replacefragmentdemo.CustomView
android:id="@+id/custom1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
com.sogia.replacefragmentdemo.CustomView
android:id="@+id/custom2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
拥有相同的 ID 可能是个问题,因为管理状态可能会变得混乱。
检查这个解决方案:
终于找到了根本原因和解决办法, 感谢@abhradeep ghosh、@Eselfar、@MadScientist 和其他回复此消息的人 post。
原因:视图 ID 应该是唯一的!否则,您的状态将被具有相同 ID 的另一个视图覆盖。在我的例子中,我有 2 个 id 为 @id/edt
的视图,所以我的状态容器只包含它的 1 个实例——以状态存储过程中最后出现的那个为准。
这是我的解决方案,(来自 this post),
首先,为视图
的保存状态创建新的classclass SavedState(superState: Parcelable) : View.BaseSavedState(superState) {
var childrenStates: SparseArray<Any>? = null
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
childrenStates?.let {
out.writeSparseArray(it)
}
}
}
在我的 CustomView
@Suppress("UNCHECKED_CAST")
public override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
val ss = SavedState(superState)
ss.childrenStates = SparseArray()
for (i in 0 until childCount) {
getChildAt(i).saveHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
}
return ss
}
@Suppress("UNCHECKED_CAST")
public override fun onRestoreInstanceState(state: Parcelable) {
val ss = state as SavedState
super.onRestoreInstanceState(ss.superState)
for (i in 0 until childCount) {
getChildAt(i).restoreHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
}
}
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
dispatchFreezeSelfOnly(container)
}
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
dispatchThawSelfOnly(container)
}