Android多片段事务排序

Android多片段事务排序,android,android-fragments,Android,Android Fragments,我有一个HorizontalScrollView包含一个(水平)LinearLayout,我使用它作为添加多个片段的容器。在进行一些更改后,我需要从该容器中删除所有片段并添加新片段。然而,当我移除旧片段时,排序似乎有问题 以下是一些场景: 应用程序启动 按此顺序正确添加片段A1,B1,C1,D1 更改内容 如果不删除初始片段,而是添加A2,B2,C2(作为单个事务),它将显示A1,B1,C1,D1,A2,B2,C2 如果删除初始片段(作为单独的事务或使用相同的事务),然后添加A2,B2,

我有一个
HorizontalScrollView
包含一个(水平)
LinearLayout
,我使用它作为添加多个片段的容器。在进行一些更改后,我需要从该容器中删除所有片段并添加新片段。然而,当我移除旧片段时,排序似乎有问题

以下是一些场景:

  • 应用程序启动
    • 按此顺序正确添加片段
      A1
      B1
      C1
      D1
  • 更改内容
    • 如果不删除初始片段,而是添加
      A2
      B2
      C2
      (作为单个事务),它将显示
      A1
      B1
      C1
      D1
      A2
      B2
      C2
    • 如果删除初始片段(作为单独的事务或使用相同的事务),然后添加
      A2
      B2
      C2
      ,它将显示
      C2
      B2
      A2
现在,我找到了一个解决方法,首先添加新片段,然后删除旧片段(仍然是同一事务的一部分),这样就可以正常工作了

编辑:该解决方案并非始终有效

我使用的是
android.support.v4.app.Fragment


你知道发生了什么事吗

作为替代解决方案,您可以尝试将视图添加到LinearLayout,然后将每个片段添加到正确的视图中。这并不理想,但似乎您无法依赖片段创建的顺序。如下所示:

ViewGroup f1 = new ViewGroup(this);
linearLayout.addView(f1);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(f1, new A2(), "mediocreworkaround");
ft.commit();
然后,当您删除所有片段时,请确保您也删除了相应的视图

linearlayout.removeAllViews();
注意:代码可能语法错误,我只是直接在StackOverflow中输入了这个。这个想法是正确的,尽管是一个普通的解决方案。不过这个问题很有意思——等我有更多时间的时候,我可能会更多地研究这个问题。弄清楚到底发生了什么。如果有,我会在这里发布更多信息

编辑:

如果让系统为您处理旋转,那么旋转应该很容易处理。为每个生成的视图添加唯一的id

//Declare a counter to ensure generated ids are different
idCounter = 1;
现在,在创建视图时使用该计数器设置ID:

//Set unique id on the view. If you really want, you can do a 
//findViewById(idCounter) == null check to ensure it's uniqueness. 
//Once you add this id, the system will take care of remembering 
//it's state for you across configuration chagne
f1.setId(idCounter++);

有一个类似的问题,我最终使用的解决方案是有多个事务。在我的例子中,只有A,B,C。我用一个事务添加A,一个事务添加B,一个事务添加C

交易顺序似乎是可靠的


如果您希望backbackback工作,可能需要更复杂的代码。但是第一个事务上的backstack标记也应该允许在那里进行适当的处理。

我在FragmentManager上启用了调试,并发现了问题

下面是日志摘录,请注意片段索引是如何按相反顺序分配的:

V/FragmentManager? Freeing fragment index TimeTracesChartFragment{42ac4910 #7 id=0x7f080044}
V/FragmentManager? add: RealTimeValuesFragment{42a567b0 id=0x7f080044}
V/FragmentManager? Allocated fragment index RealTimeValuesFragment{42a567b0 #7 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d35c38 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d35c38 #6 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d35e98 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d35e98 #5 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d36220 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d36220 #4 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d39d18 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d39d18 #3 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d3a170 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d3a170 #2 id=0x7f080044}
V/FragmentManager? add: TimeTracesChartFragment{42d3a528 id=0x7f080044}
V/FragmentManager? Allocated fragment index TimeTracesChartFragment{42d3a528 #1 id=0x7f080044}
V/FragmentManager? moveto CREATED: TimeTracesChartFragment{42d3a528 #1 id=0x7f080044}
以下是罪犯代码:

其中,
FragmentTransactionBugFixHack
如下所示:

package android.support.v4.app;

import java.util.Collections;

public class FragmentTransactionBugFixHack {

    public static void reorderIndices(FragmentManager fragmentManager) {
        if (!(fragmentManager instanceof FragmentManagerImpl))
            return;
        FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
        if (fragmentManagerImpl.mAvailIndices != null)
            Collections.sort(fragmentManagerImpl.mAvailIndices, Collections.reverseOrder());
    }

}

这并不理想,因为这两个单独的事务将闪烁为白色(或无论您的容器的背景是什么),但至少它会正确排序。

解决此问题的其他方法:

将ArrayList MavailIndexes替换为ReverseOrderArrayList

reverseOrderaryList.java

public类reverseOrderaryList扩展了ArrayList{
@凌驾
公共布尔加法(T对象){
布尔值=super.add(对象);
Collections.sort(this,Collections.reverseOrder());
返回值;
}
@凌驾
公共void add(int索引,T对象){
super.add(索引、对象);
Collections.sort(this,Collections.reverseOrder());
}
@凌驾
公共布尔addAll(集合集合){
布尔值=super.removeAll(集合);
Collections.sort(this,Collections.reverseOrder());
返回值;
}
@凌驾
公共T删除(整型索引){
T值=超级删除(索引);
Collections.sort(this,Collections.reverseOrder());
返回值;
}
}

公共类FragmentTransactionBugFixHack{
私有静态最终字符串TAG=“FragmentTransactionBugFixHack”;
公共静态无效注入碎片事务可用性指示自动反转顺序(碎片管理器碎片管理器){
试一试{
Log.d(标记“注入碎片事务可用性指示自动反转顺序”);
if(fragmentManager==null | |!(fragmentManager instanceof FragmentManagerImpl))返回;
FragmentManagerImpl FragmentManagerImpl=(FragmentManagerImpl)fragmentManager;
if(fragmentManagerImpl.mavailIndexes!=null&&fragmentManagerImpl.mavailIndexes instanceof reverseOrderaryList)返回;
ArrayList backupList=fragmentManagerImpl.MavailIndexes;
fragmentManagerImpl.MavailIndexes=新的ReverseOrderArrayList();
if(backupList!=null){
fragmentManagerImpl.MavailIndexes.addAll(backupList);
}
Log.d(标签“注入正常”);
}捕获(例外e){
Log.e(TAG,e);
}
}}
使用: 调用FragmentTransaction BugFixHack.InjectFragmentTransaction可用性指示创建活动中的自动反转顺序


这里是一个稍微修改的版本,我在最后添加了递归部分。这将对给定片段管理器、其所有片段的ChildFragmentManager和所有这些片段的ChildFragmentManager的索引进行重新排序,以此类推

这是您添加到项目中的一个新类(您可以将一个包
android.support.v4.app
添加到源代码的
java
文件夹中,并将其放入该包中,这对我很有用):


这是一个有趣的想法,我将试一试。这似乎是可行的,但处理旋转也需要太多的工作-我需要保存生成的视图ID并还原它们,否则它不知道将碎片附加到何处…我将尝试查找问题,也许还有另一个解决办法。编辑帖子来处理你的方法的方向变化
removalTxn.commit();
getSupportFragmentManager().executePendingTransactions();
FragmentTransactionBugFixHack.reorderIndices(getSupportFragmentManager());
//create additionTxn
additionTxn.commit();
package android.support.v4.app;

import java.util.Collections;

public class FragmentTransactionBugFixHack {

    public static void reorderIndices(FragmentManager fragmentManager) {
        if (!(fragmentManager instanceof FragmentManagerImpl))
            return;
        FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
        if (fragmentManagerImpl.mAvailIndices != null)
            Collections.sort(fragmentManagerImpl.mAvailIndices, Collections.reverseOrder());
    }

}
public class ReverseOrderArrayList<T extends Comparable> extends ArrayList<T> {
@Override
public boolean add(T object) {
    boolean value = super.add(object);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}

@Override
public void add(int index, T object) {
    super.add(index, object);
    Collections.sort(this, Collections.reverseOrder());
}

@Override
public boolean addAll(Collection<? extends T> collection) {
    boolean value = super.addAll(collection);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}

@Override
public boolean addAll(int index, Collection<? extends T> collection) {
    boolean value = super.addAll(index, collection);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}

@Override
protected void removeRange(int fromIndex, int toIndex) {
    super.removeRange(fromIndex, toIndex);
    Collections.sort(this, Collections.reverseOrder());
}

@Override
public boolean remove(Object object) {
    boolean value = super.remove(object);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}

@Override
public boolean removeAll(Collection<?> collection) {
    boolean value = super.removeAll(collection);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}

@Override
public T remove(int index) {
    T value = super.remove(index);
    Collections.sort(this, Collections.reverseOrder());
    return value;
}
public class FragmentTransactionBugFixHack {
private static final String TAG = "FragmentTransactionBugFixHack";

public static void injectFragmentTransactionAvailIndicesAutoReverseOrder(FragmentManager fragmentManager) {
    try {
        Log.d(TAG, "injection injectFragmentTransactionAvailIndicesAutoReverseOrder");
        if (fragmentManager==null || !(fragmentManager instanceof FragmentManagerImpl)) return;
        FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
        if (fragmentManagerImpl.mAvailIndices!=null && fragmentManagerImpl.mAvailIndices instanceof ReverseOrderArrayList) return;
        ArrayList<Integer> backupList = fragmentManagerImpl.mAvailIndices;
        fragmentManagerImpl.mAvailIndices = new ReverseOrderArrayList<>();
        if (backupList!=null) {
            fragmentManagerImpl.mAvailIndices.addAll(backupList);
        }
        Log.d(TAG, "injection ok");
    } catch (Exception e) {
        Log.e(TAG, e);
    }
}}
package android.support.v4.app;

public class FragmentTransactionBugFixHack {

    public static void reorderIndices(FragmentManager fragmentManager) {
        if (!(fragmentManager instanceof FragmentManagerImpl))
            return;
        FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
        if (fragmentManagerImpl.mAvailIndices != null) {
            Collections.sort(fragmentManagerImpl.mAvailIndices, Collections.reverseOrder());
        }

        //Recursively reorder indices of all child fragments.
        List<Fragment> fragments = fragmentManager.getFragments();
        //The support library FragmentManager returns null if none.
        if(fragments != null) {
            for (Fragment fragment : fragments) {
                //For some reason, the fragments in the list of fragments might be null.
                if(fragment != null) {
                    reorderIndices(fragment.getChildFragmentManager());
                }
            }
        }
    }
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    FragmentTransactionBugFixHack.reorderIndices(getSupportFragmentManager());
}