解决了。哦,我走过的兔子洞……无论如何,如果你遇到这样的问题,需要考虑以下几点:
- 最终我不必在
onSaveInstanceState(Bundle outState)
.
- 最终,我不必考虑在
onSaveInstanceState
活动中处理 backstack 或处理它onCreate
。
- 当第一次以编程方式将片段“添加”到 FrameLayout 时,请使用
replace
而不是“添加”——这可能是我麻烦的根源之一。
- 在 onCreate 检查 savedInstanceState 的 bundle 是否为 null,
if(savedInstanceState == null)
如果是,那么我知道该活动之前没有因配置更改而被拆除,所以在这里我构建了应该在活动启动时显示的片段。以编程方式在其他地方(即,晚于活动onCreate()
)的其他片段,它们不属于if
,它们属于else
:
else onSaveInstanceState != null
而且我知道这件事不为空只有一个原因,因为系统在其中创建了一个名为 outState 的包并将其放入onSaveInstanceState(Bundle outState)
活动的onCreate
方法中,我现在可以在其中获取我的垃圾。所以在这里我知道了几件事:
- 当然,我在活动中创建的片段
onCreate
仍然是活动的一部分(我没有分离或销毁它们),但是,我不能对通过用户的行为赋予生命的片段提出同样的要求,这些片段可能或当前(在定向又名配置更改时)可能未附加到活动。
- 这是一个
if-this-thing-is-attached
条款的好地方。我最初搞砸的一件事是我没有给我所有以编程方式添加的片段一个标签;给所有以编程方式添加的片段标签。然后我可以找出 savedInstanceState 包是否包含该键 withsavedInstanceState.containsKey(MY_FRAG_TAG)
和 withgetFragmentManager().findFragmentByTag(MY_FRAG_TAG)
所以这里是活动的 onCreate(简化):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
// fragments that may not be in the bundle
if(savedInstanceState.containsKey(EDIT_ITEM_TAG)){
editItemFragment = (FragmentC)getFragmentManager().getFragment(savedInstanceState, EDIT_ITEM_TAG);
}
}
// This fragment is NOT programmatically added, ie, it is statically found in an XML file.
// Hence, the system will take care of preserving this fragment on configuration changes.
listFrag = (ListViewFragment)getFragmentManager().findFragmentById(R.id.ListFragment);
// create adapter
adapter = new EditCursorAdapter(this, null);
// set list fragment adapter
listFrag.setListAdapter(adapter);
// prepare the loader
getLoaderManager().initLoader(LOADER_ID, null, this);
}
以及 Activity 的列表片段侦听器,其中 FragmentC 被交换为 FragmentA:
// listfragment listener
@Override
public void listFragListener(Cursor cursor) {
// checking backstack size
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
// With each listview click there should be only one item in the backstack.
getFragmentManager().popBackStack();
// create new fragment
editItemFragment = FragmentC.newInstance(cursor);
// programmatically add new fragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.edit_topFrame, editItemFragment, EDIT_ITEM_TAG);
ft.addToBackStack("pop all of these"); // was testing different ways of popping
ft.commit();
// interesting: this reports the same value as the first log in this method.
// ...clearly addToBackStack(null).commit() doesn't populate the backstack immediately?
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
}
而 onSaveInstanceState 就像一只松鸦一样赤裸裸:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
摘要:我的活动完全按照我的意愿运作。
现在,如果我有一堆添加的片段,那么我可能会以更加程序化的方式处理它们,而不是硬编码if(savedInstanceState.contains(*hard coded key*)
. 我对此进行了一些测试,但无法证明其功效,但是对于那里的人来说,这可能会激发您对可以做什么的想法:
制作一组私有的添加片段:
// Collection of Frag Tags
private Set<String> AddedFragmentTagsSet = new HashSet<String>();
在onAttachFragment
做类似的事情:
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// logging which fragments get attached and when
Log.d(TAG, SCOPE +"attached fragment: " +fragment.toString());
// NOTE: XML frags have not frigg'n tags
// add attached fragment's tag to set of tags for attached fragments
AddedFragmentTagsSet.add(fragment.getTag());
// if a fragment has become detached remove its tag from the set
for(String tag : AddedFragmentTagsSet){
if(getFragmentManager().findFragmentByTag(tag).isDetached()){
AddedFragmentTagsSet.remove(tag);
}
Log.d(TAG, SCOPE +"contents of AddedFragmentTagsSet: " +tag);
}
}
然后在活动的onCreate
和内的savedInstanceState
子句中:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
//////////// find entries that are common to AddedFragmentTagsSet & savedInstanceState's set of keys ///////////
Set<String> commonKeys = savedInstanceState.keySet();
commonKeys.retainAll(AddedFragmentTagsSet);
for(String key : commonKeys){
editItemFragment = FragmentC)getFragmentManager().getFragment(savedInstanceState, key);
}
}
}
...但这未经测试,只是为了激发想法而提出;在试图找出我的活动处理配置更改的问题时,我确实在这个方向上磕磕绊绊,并认为它可能会为合适的人带来成果;尽管最终,显然,这次我找到了一种更简单的方法来解决我的问题。