タブモードでActionBarSherlockを使用して構成されるアプリケーションがあります。5つのタブがあり、各タブのコンテンツはフラグメントを使用して処理されます。ただし、tab2には、xmlファイルにViewPager要素が含まれているフラグメントがあり、ViewPager要素にはいくつかのフラグメントページがあります。最初にアプリケーションを起動すると、問題なくタブを切り替えることができますが、2回目にtab2を押すと、上記のエラーが発生します。主な活動は次のとおりです。
public class MainActivity extends SherlockFragmentActivity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
ActionBar.Tab tab1 = actionBar.newTab().setText("Tab1");
ActionBar.Tab tab3 = actionBar.newTab().setText("Tab3");
ActionBar.Tab tab2 = actionBar.newTab().setText("Tab2");
ActionBar.Tab tab4 = actionBar.newTab().setText("Tab4");
ActionBar.Tab tab5 = actionBar.newTab().setText("Tab5");
Fragment fragment1 = new Tab1();
Fragment fragment3 = new Tab3();
Fragment fragment2 = new Tab2();
Fragment fragment5 = new Tab5();
Fragment fragment4 = new Tab4();
tab1.setTabListener(new MyTabListener(fragment1));
tab3.setTabListener(new MyTabListener(fragment3));
tab2.setTabListener(new MyTabListener(fragment2));
tab5.setTabListener(new MyTabListener(fragment5));
tab4.setTabListener(new MyTabListener(fragment4));
actionBar.addTab(tab1);
actionBar.addTab(tab2);
actionBar.addTab(tab3);
actionBar.addTab(tab4);
actionBar.addTab(tab5);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
class MyTabListener implements ActionBar.TabListener
{
Fragment fragment;
public MyTabListener(Fragment fragment)
{
this.fragment = fragment;
}
@Override
public void onTabSelected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft)
{
ft.replace(R.id.fragment_container,fragment);
}
@Override
public void onTabUnselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft)
{
}
@Override
public void onTabReselected(com.actionbarsherlock.app.ActionBar.Tab tab,FragmentTransaction ft)
{
}
}
}
ViewPagerのないフラグメントクラスは次のとおりです。
public class Tab1 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
return inflater.inflate(R.layout.activity_tab1, container, false);
}
}
ViewPagerのフラグメントクラスは次のとおりです。
public class Tab2 extends Fragment
{
ViewPager mViewPager;
private MyFragmentPagerAdapter mMyFragmentPagerAdapter;
private static int NUMBER_OF_PAGES = 5;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.activity_tab2, container, false);
return view;
}
@Override
public void onViewCreated(View view,Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
mViewPager.setAdapter(mMyFragmentPagerAdapter);
}
private static class MyFragmentPagerAdapter extends FragmentPagerAdapter
{
public MyFragmentPagerAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public Fragment getItem(int index)
{
return PageFragment.newInstance("My Message " + index);
}
@Override
public int getCount()
{
return NUMBER_OF_PAGES;
}
}
}
私が別の場所で読んだものから(そして間違っている場合は私を修正してください)、これは2回目のパスのフラグメントマネージャがもう存在しないアクティビティからフラグメントを再利用しようとするために発生し、エラーが発生します。しかし、フラグメントアクティビティを使用していないので、なぜここでこれが起こるのかわかりません。 logcatによると、エラーはTab2クラス、mViewPager.setAdapter(mMyFragmentPagerAdapter)と書かれている行のonViewCreatedメソッドにあります。どんな助けも大歓迎です...ありがとう。
03-04 12:01:05.468: E/AndroidRuntime(2474): FATAL EXCEPTION: main
03-04 12:01:05.468: E/AndroidRuntime(2474): Java.lang.IllegalStateException: Activity has been destroyed
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1342)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:595)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.Java:578)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.Java:139)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.view.ViewPager.populate(ViewPager.Java:1011)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.view.ViewPager.populate(ViewPager.Java:880)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.view.ViewPager.setAdapter(ViewPager.Java:433)
03-04 12:01:05.468: E/AndroidRuntime(2474): at com.example.tabs.Tab2.onViewCreated(Tab2.Java:31)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:925)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1088)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.BackStackRecord.run(BackStackRecord.Java:682)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1444)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:429)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.os.Handler.handleCallback(Handler.Java:587)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.os.Handler.dispatchMessage(Handler.Java:92)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.os.Looper.loop(Looper.Java:123)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Android.app.ActivityThread.main(ActivityThread.Java:3687)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Java.lang.reflect.Method.invokeNative(Native Method)
03-04 12:01:05.468: E/AndroidRuntime(2474): at Java.lang.reflect.Method.invoke(Method.Java:507)
03-04 12:01:05.468: E/AndroidRuntime(2474): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:842)
03-04 12:01:05.468: E/AndroidRuntime(2474): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:600)
03-04 12:01:05.468: E/AndroidRuntime(2474): at dalvik.system.NativeStart.main(Native Method)
これは、ネストされたフラグメントに新しく追加されたサポートのバグのようです。基本的に、子FragmentManager
は、アクティビティから切り離されると、内部状態が壊れてしまいます。私のために修正した短期的な回避策は、onDetach()
を呼び出すすべてのFragment
のgetChildFragmentManager()
に以下を追加することです。
@Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
私はまったく同じ問題を抱えています。私が見つけた唯一の回避策は、タブが変更されるたびに、フラグメントを新しいインスタンスに置き換えることです。
ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));
実際のソリューションではありませんが、以前のフラグメントインスタンスを再利用する方法が見つかりませんでした...
メソッドの最後でsuper.onCreate()
を呼び出したときに同じ問題が発生しました。理由:attachActivity()
はFragmentActivityのonCreate()で呼び出されます。 onCreate()
をオーバーライドし、たとえばタブを作成すると、タブマネージャーはFragmentManagerにアタッチされたアクティビティを持たずにフラグメントに切り替えようとします。
簡単な解決策:super.onCreate()
への呼び出しを関数本体の先頭に移動します。
一般的に、この問題が発生する理由はたくさんあるようです。これは別のものです...
マティアス
super.onCreate()
を呼び出す前にonCreateでFragmentTransaction
を作成しようとしたアクティビティに問題があることを追加したいと考えました。 super.onCreate()
を関数の一番上に移動したところ、うまくいきました。
LocalBroadcastManagerを使用していたため、このエラーが発生しました。
unregisterReceiver(intentReloadFragmentReceiver);
の代わりに:
LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);
同じ問題に遭遇し、後で、FragmentActivityのsuper.onCreate( savedInstanceState );
でonCreate()
への呼び出しを見逃していることがわかりました。
OnPauseで子フラグメントを含むフラグメントをNULLに強制すると、問題が修正されます
fragment = null;
フラグメントが完全に初期化される前に子FragmentManager
にアクセスしようとすると、まったく同じエラーが発生しました(つまり、Activityにアタッチされるか、少なくともonCreateView()
が呼び出されます)。そうでない場合、FragmentManager
はnull
アクティビティで初期化され、前述の例外が発生します。
私はこれが古い投稿であることを知っていますが、提案された答えは私の側ではうまくいきませんでした。誰かがそれを役に立つと思うかもしれないので、私はこれをここに残したいです。
私がしたことは:
@Override
public void onResume() {
super.onResume();
// add all fragments
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
for(Fragment fragment : fragmentPages){
String tag = fragment.getClass().getSimpleName();
fragmentTransaction.add(R.id.contentPanel, fragment, tag);
if(fragmentPages.indexOf(fragment) != currentPosition){
fragmentTransaction.hide(fragment);
} else {
lastTag = tag;
}
}
fragmentTransaction.commit();
}
次に:
@Override
public void onPause() {
super.onPause();
// remove all attached fragments
for(Fragment fragment: fragmentPages){
getChildFragmentManager().beginTransaction().remove(fragment).commit();
}
}
私はこの問題を抱えていて、ここで解決策を見つけることができなかったので、他の誰かが再びこの問題を抱えている場合に備えて、解決策を共有したいと思います。
私はこのコードを持っていました:
public void finishAction() {
onDestroy();
finish();
}
行「onDestroy();」を削除して問題を解決しました
public void finishAction() {
finish();
}
私が初期コードを書いた理由:「finish()」を実行するとアクティビティが「onDestroy()」を呼び出すことを知っていますが、スレッドを使用しており、次のアクティビティを開始する前にすべてのスレッドを確実に破棄したかったです、そして、「finish()」は常に即時ではないように見えます。多くの「ビットマップ」を処理/削減し、大きな「ビットマップ」を表示する必要があり、アプリのメモリ使用量の改善に取り組んでいます
次に、別のメソッドを使用してスレッドを強制終了し、このメソッドを「onDestroy();」から実行しますそして、私はすべてのスレッドを殺す必要があると思うとき。
public void finishAction() {
onDestroyThreads();
finish();
}
これにより、Xamarinに夢中になりました。
Fragment内のTabLayoutのViewPager実装でこれに遭遇しました。それ自体はDrawerLayoutに実装されています。
- DrawerLayout
- DrawerFragment
- TabLayout
- TabViewPager
- TabViewPagerFragments
したがって、DrawerFragmentに次のコードを実装する必要があります。正しいFragmentManager-Pathを選択することに注意してください。 2つの異なるFragmentManager参照がある可能性があるためです。
->使用するものを選択します。 ChildFragmentManagerを使用する場合は、ViewPagerにクラス宣言Android.App.FragmentManagerを使用する必要がありました。
Android.Support.V4.App.FragmentManager
「メイン」フラグメントに次のメソッドを実装します-この例では:DrawerFragment
public override void OnDetach() {
base.OnDetach();
try {
Fragment x = this;
var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/support/v4/app/FragmentManagerImpl;");
JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
}
catch (Exception e) {
Log.Debug("Error", e+"");
}
}
Android.App.FragmentManager
public class TabViewPager: Android.Support.V13.App.FragmentPagerAdapter {}
つまり、Android.App.FragmentManagerでViewPagerを初期化する必要がありました。
「メイン」フラグメントに次のメソッドを実装します-この例では:DrawerFragment
public override void OnDetach() {
base.OnDetach();
try {
Fragment x = this;
var classRefProp = typeof(Fragment).GetProperty("class_ref", BindingFlags.NonPublic | BindingFlags.Static);
IntPtr classRef = (IntPtr)classRefProp.GetValue(x);
var field = JNIEnv.GetFieldID(classRef, "mChildFragmentManager", "Landroid/app/FragmentManagerImpl;");
JNIEnv.SetField(base.Handle, field, IntPtr.Zero);
}
catch (Exception e) {
Log.Debug("Error", e+"");
}
}
この問題があり、Activity
のonCreate
でsetContentView(int id)
を2回呼び出していたことが原因であることに気付きました。