我创建了一个小测试应用程序,它代表了我的问题。我使用ActionBarSherlock来用(Sherlock)片段实现选项卡。
我的代码:TestActivity.java
public class TestActivity extends SherlockFragmentActivity { private ActionBar actionBar; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupTabs(savedInstanceState); } private void setupTabs(Bundle savedInstanceState) { actionBar = getSupportActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); addTab1(); addTab2(); } private void addTab1() { Tab tab1 = actionBar.newTab(); tab1.setTag("1"); String tabText = "1"; tab1.setText(tabText); tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "1", MyFragment.class)); actionBar.addTab(tab1); } private void addTab2() { Tab tab1 = actionBar.newTab(); tab1.setTag("2"); String tabText = "2"; tab1.setText(tabText); tab1.setTabListener(new TabListener<MyFragment>(TestActivity.this, "2", MyFragment.class)); actionBar.addTab(tab1); } }
TabListener.java
public class TabListener<T extends SherlockFragment> implements com.actionbarsherlock.app.ActionBar.TabListener { private final SherlockFragmentActivity mActivity; private final String mTag; private final Class<T> mClass; public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) { mActivity = activity; mTag = tag; mClass = clz; } /* The following are each of the ActionBar.TabListener callbacks */ public void onTabSelected(Tab tab, FragmentTransaction ft) { SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); // Check if the fragment is already initialized if (preInitializedFragment == null) { // If not, instantiate and add it to the activity SherlockFragment mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName()); ft.add(android.R.id.content, mFragment, mTag); } else { ft.attach(preInitializedFragment); } } public void onTabUnselected(Tab tab, FragmentTransaction ft) { SherlockFragment preInitializedFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag); if (preInitializedFragment != null) { // Detach the fragment, because another one is being attached ft.detach(preInitializedFragment); } } public void onTabReselected(Tab tab, FragmentTransaction ft) { // User selected the already selected tab. Usually do nothing. } }
MyFragment.java
public class MyFragment extends SherlockFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { try { Thread.sleep(2000); } catch (InterruptedException ex) { } return null; } @Override protected void onPostExecute(Void result){ getResources().getString(R.string.app_name); } }.execute(); } }
我增加了Thread.sleep
部分模拟下载数据中的代码onPostExecute
是模拟使用Fragment
...
当我在景物和肖像之间快速旋转屏幕时,我在onPostExecute
代码:
java.lang.IllegalStateException: Fragment MyFragment{410f6060} not attached to Activity
我认为这是因为同时创建了一个新的MyFragment
,并且在AsyncTask
完成之前附加到Activity
。 onPostExecute
中的代码调用一个未连接的MyFragment
。
但是我怎样才能解决这个问题?
当带有加载首选项的应用程序设置活动可见时,我遇到了类似的问题。如果我要更改其中一个首选项,然后使显示内容旋转并再次更改首选项,它将崩溃,其中会出现一个消息,即片段(MyPreferences类)没有附加到活动中。
调试时,当显示内容旋转时,它看起来就像PreferencesFrament的onCreate()方法被调用了两次。已经够奇怪的了。然后,我在块之外添加了isAdded()检查,它将指示崩溃,并解决了这个问题。
以下是更新首选项摘要以显示新条目的侦听器代码。它位于MyPreferences类的onCreate()方法中,它扩展了PreferenceFrage类:
public static class Preferences extends PreferenceFragment { SharedPreferences.OnSharedPreferenceChangeListener listener; @Override public void onCreate(Bundle savedInstanceState) { // ... listener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { // check if the fragment has been added to the activity yet (necessary to avoid crashes) if (isAdded()) { // for the preferences of type "list" set the summary to be the entry of the selected item if (key.equals(getString(R.string.pref_fileviewer_textsize))) { ListPreference listPref = (ListPreference) findPreference(key); listPref.setSummary("Display file content with a text size of " + listPref.getEntry()); } else if (key.equals(getString(R.string.pref_fileviewer_segmentsize))) { ListPreference listPref = (ListPreference) findPreference(key); listPref.setSummary("Show " + listPref.getEntry() + " bytes of a file at once"); } } } }; // ... }