我有一个HorizontalScrollView,它包含一个(水平的) LinearLayout,用作添加多个片段的容器。在进行一些更改时,我需要从该容器中删除所有片段并添加新的片段。然而,当我移除旧的片段时,排序似乎有问题。
以下是几种情况:
A1、B1、C1、D1
A2、B2、C2 (作为单个事务),则将显示A1、B1、C1、D1、A2、B2、C2A2、B2、C2,它将显示C2、B2、A2
现在,我找到了一个解决办法,首先添加新的片段,然后删除旧的片段(仍然是同一事务的一部分),这是正常工作的。
编辑:解决方案并不总是有效的。
我在用android.support.v4.app.Fragment。
对发生了什么事有什么想法吗?
发布于 2014-05-07 17:01:20
我在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}这是罪魁祸首代码:
r1/android/support/v4/app/FragmentManager.java#FragmentManagerImpl.makeActive%28android.support.v4.app.Fragment%29
void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}
if (mAvailIndices == null || mAvailIndices.size() <= 0) {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
f.setIndex(mActive.size(), mParent);
mActive.add(f);
} else {
f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
}请注意,可用的索引是如何从列表后面提取的。它可能应该选择可用的最低索引,以便保持排序。
现在想个办法..。
编辑:
下面是一个解决办法:创建两个单独的事务,一个用于删除,另一个用于添加,然后执行以下操作:
removalTxn.commit();
getSupportFragmentManager().executePendingTransactions();
FragmentTransactionBugFixHack.reorderIndices(getSupportFragmentManager());
//create additionTxn
additionTxn.commit();其中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());
}
}这并不理想,因为这两个单独的事务会闪烁到白色(或者不管您的容器的背景是什么),但至少它会正确地对它们进行排序。
发布于 2015-03-16 08:17:16
解决这一问题的其他方法:
将ArrayList mAvailIndices替换为ReverseOrderArrayList
ReverseOrderArrayList.java
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);
}
}}使用:在活动-onCreate中调用FragmentTransactionBugFixHack.injectFragmentTransactionAvailIndicesAutoReverseOrder。
发布于 2014-05-06 22:10:30
作为另一种解决方法,您可以尝试向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;现在,在创建视图时使用该计数器设置ids:
//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++);https://stackoverflow.com/questions/23504790
复制相似问题