代码之家  ›  专栏  ›  技术社区  ›  GianhTran

在弹出片段后,所有editext都将替换为相同的值

  •  -1
  • GianhTran  · 技术社区  · 7 年前

    我有一个奇怪的问题,我有2个片段,在第一个片段中,我有一些自定义的 edittext ,并且有一个按钮将其替换为第二个片段( addtobackstack =true),然后,在第二个片段中,我尝试使用 popbackbackstack() to back to first fragment,the issue occurrence,all custom edittext have same价值。

    以下是我的全部代码

    第一个片段

    class firstfragment:basefragment()。{
    覆盖fun oncreateView(充气器:布局充气器,容器:视图组)?,
    savedinstancestate:捆绑?)视野?{
    返回充气器。充气(r.layout.fragment ou first,container,false)
    }
    
    覆盖fun onviewcreated(视图:视图,savedinstancestate:bundle?){
    super.onviewcreated(视图,savedinstanceState)
    下一个.setonclicklistener{
    val transaction=RequireActivity().SupportFragmentManager!!.BeginTransaction())
    .replace(r.id.contentframe,secondfragment(),“”)
    CommittTransaction(事务,真,-1)
    }
    }
    }
    < /代码> 
    
    

    第二个片段

    class secondFragment:baseFragment()。{
    覆盖fun oncreateView(充气器:布局充气器,容器:视图组)?,
    savedinstancestate:捆绑?)视野?{
    返回充气器。充气(r.layout.fragment_second,container,false)
    }
    
    覆盖fun onviewcreated(视图:视图,savedinstancestate:bundle?){
    super.onviewcreated(视图,savedinstanceState)
    返回.setonclicklistener{
    RequireActivity().SupportFragmentManager.PopBackback()。
    }
    }
    }
    < /代码> 
    
    

    片段优先.xml

    <?xml version=“1.0”encoding=“utf-8”?gt;
    <linearlayout xmlns:android=“http://schemas.android.com/apk/res/android”
    android:layout_width=“匹配父级”
    android:layout_height=“匹配父级”
    android:orientation=“垂直”
    gt;
    <com.sogia.replaceFragmentDemo.customView(lt;com.sogia.replaceFragmentDemo.customView)
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    /gt;
    
    <com.sogia.replaceFragmentDemo.customView(lt;com.sogia.replaceFragmentDemo.customView)
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    /gt;
    按钮
    android:id=“@+id/btn\u下一步”
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    android:text=“下一步”
    /gt;
    </linearlayout>
    < /代码> 
    
    

    片段第二.xml

    <?xml version=“1.0”encoding=“utf-8”?gt;
    <linearlayout xmlns:android=“http://schemas.android.com/apk/res/android”
    android:layout_width=“匹配父级”
    android:layout_height=“匹配父级”
    gt;
    按钮
    android:id=“@+id/btn返回”
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    android:text=“上一步”
    /gt;
    </linearlayout>
    < /代码> 
    
    

    自定义视图

    class customview@jvmoverloads constructor(
    上下文:上下文,attrs:attributeset?=空,defStyleAttr:int=0
    ):linearlayout(上下文、属性、defstyleattr){
    init {
    充气(上下文,r.layout.layout_custom_view,this)
    }
    }
    < /代码> 
    
    

    布局\自定义\视图.xml

    <?xml version=“1.0”encoding=“utf-8”?gt;
    <linearlayout xmlns:android=“http://schemas.android.com/apk/res/android”
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    gt;
    编辑文本
    安卓:id=“@+id/edt”
    android:layout_width=“匹配父级”
    android:layout_height=“包装内容”
    android:hint=“输入某物”
    /gt;
    </linearlayout>
    < /代码> 
    
    

    如有任何回应,我们将不胜感激。addToBackStack=true),然后,在第二个片段中,我尝试使用popBackStack()回到第一个片段,问题就出现了,所有自定义编辑文本具有相同的值。

    error

    以下是我的全部代码

    第一片段

    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\u 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>
    

    片段\u 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)
        }
    }
    

    布局\自定义\视图.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>
    

    如有任何回应,我们将不胜感激。

    4 回复  |  直到 7 年前
        1
  •  3
  •   MadScientist    7 年前

    您没有添加到后堆栈,您正在替换,尝试打开第二个片段,这将保持第一个片段的状态不变,并且在堆栈中。

    btn_next.setOnClickListener {
                val transaction = requireActivity().supportFragmentManager!!.beginTransaction()
                    .add(R.id.contentFrame, SecondFragment(), "")
                commitTransaction(transaction, true, -1)
            }
    

    也是你们两个 EditText 有相同的身份证 android:id="@+id/edt" 因此运行的合成器功能 findViewById 将指向 编辑文本

        2
  •  1
  •   sebasira    7 年前

    我将尝试向布局中的每个自定义视图添加不同的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"
        />
    
        3
  •  1
  •   GianhTran    7 年前

    最后我找到了根本原因和解决办法, 感谢@abhradeep ghosh,@eselfar,@madcastient和另一位回复此帖的人。

    原因:视图ID应该是唯一的!否则,您的状态将被另一个具有相同ID的视图覆盖。在我的示例中,我有两个具有ID的视图 @id/edt ,所以我的状态容器只保存它的一个实例-以状态存储过程中最后出现的为准。

    这是我的解决方案 this post )

    首先,为保存视图状态创建新类

    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)
        }
    
        4
  •  0
  •   abhradeep ghosh    7 年前

    拥有相同的ID可能是一个问题,因为管理状态可能会变得混乱。 请检查此解决方案: Restore fragment with two views having the same id