ViewPagerでタブを使用すると「Java.lang.IllegalStateExceptionアクティビティが破棄されました」というエラーが発生する


110

タブモードで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)

だから私は問題を発見したかもしれないと思います。Eclipseデバッガーを通じて変数mMyFragmentPagerAdapter(クラスTab2)を見ると、Tab2を初めてクリックしたときに、MainActivityを指すmActivityと呼ばれるフィールドがあったFragmentManager変数があったことがわかりました。他のタブとmActivityをもう一度見てみると、nullの値があり、これが原因でエラーActivityが破棄された理由を説明している可能性があります。
Yulric Sequeira 2013

回答:


284

これは、ネストされたフラグメントの新しく追加されたサポートのバグのようです。基本的に、子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);
    }
}

21
Fragmentの実装を見ると、detached状態に移行すると、内部状態がリセットされることがわかります。ただし、mChildFragmentManagerはリセットされません(これは現在のバージョンのサポートライブラリのバグです)。これにより、フラグメントが再接続されたときに子フラグメントマネージャが再接続されず、表示された例外が発生します。
Marcus Forsell Stahre 2013

14
あなたは私をからかっている必要があります。あなたがこの投稿を見つけてうれしいですが、良い悲しみです。
セキュアブート2013

8
このバグは、Androidオープンソースの課題トラッカーで追跡されています:code.google.com/p/android/issues/detail?id
Kristopher Johnson

3
ちょっとした塩味ですが、support-v4バージョンまたはandroid.appバージョンを使用すると失敗します。バグがないだけサポートライブラリに起こるように
gbero

6
サポートライブラリバージョン24.0.0で修正されたようです。「android.support.v4.app.Fragment」の「performDetach()」メソッドは、「mChildFragmentManager = null;」を実行します。
Emerson Dallagnol 16

13

私はまったく同じ問題を抱えています。私が見つけた唯一の回避策は、タブが変更されるたびに、フラグメントを新しいインスタンスで置き換えることです。

ft.replace(R.id.fragment_container, Fragment.instantiate(PlayerMainActivity.this, fragment.getClass().getName()));

実際の解決策ではありませんが、以前のフラグメントインスタンスを再利用する方法が見つかりません...


1
ワウ、ありがとう...それで問題が解決しました。なぜ機能するのかを説明することはできますか?FragmentManagerを使用してエラーを修正しようとして頭を壊していました。
Yulric Sequeira 2013

1
メモリフットプリントを分析しましたか?この回避策で増加する可能性があるため、少なくとも疑わしい
nmxprime 14年

なぜ動作するかわからない..動作方法はわからないが動作するlol

7

super.onCreate()メソッドの最後に呼び出すときに同じ問題が発生しました。理由:attachActivity()FragmentActivityのonCreate()で呼び出されます。オーバーライドonCreate()して、たとえばタブを作成する場合、TabマネージャーはFragmentManagerにアタッチされたアクティビティがない状態でフラ​​グメントに切り替えようとします。

簡単な解決策:への呼び出しをsuper.onCreate()関数本体の先頭に移動します。

一般に、この問題が発生する理由はたくさんあります。これはただの別のものです...

マティアス


どうもありがとう、あなたは私の日を救った!私は同じ問題を抱えていましたが、1週間経ってもそれを解決できませんでした;(。この回答を書いてとても嬉しい!!!
JonasPTFL

4

私の問題は、FragmentTransaction私が呼び出す前にonCreateでin を作成しようとしたアクティビティにあったことを付け加えたいと思いsuper.onCreate()ます。私super.onCreate()は関数の一番上に移動し、うまくいきました。


2

LocalBroadcastManagerを使用していたため、このエラーが発生しました。

unregisterReceiver(intentReloadFragmentReceiver);

の代わりに:

LocalBroadcastManager.getInstance(this).unregisterReceiver(intentReloadFragmentReceiver);

1
これは私の問題を解決しません。しかし、おかげでBroadcastReceiversの使用に関する私の間違いを修正するのに役立ちました
nmxprime '20

アクティビティコンテキストがnullの場合はどうなりますか。その場合、「これ」は無効になります。
IgorGanapolsky 2015

アクティビティコンテキストをnullにできる場合 私は決して思いません。
Malachiasz 2015


1

FragmentManagerフラグメントが完全に初期化される前に子にアクセスしようとすると、まったく同じエラーが発生しました(つまり、アクティビティにアタッチされているか、少なくともonCreateView()呼び出されています)。それ以外の場合FragmentManagernull、前述の例外を引き起こすアクティビティで初期化されます。


1

onPauseで子フラグメントを含むフラグメントを強制的にNULLにすると、問題が解決します

fragment = null;

1

私はこれが古い投稿であることを知っていますが、提案された答えは私の側ではうまくいきませんでした。誰かが役に立つと思う場合に備えて、ここに置いておきます。

私がしたことは:

@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();
    }
}

0

私はこの問題を抱えていて、ここで解決策を見つけることができなかったので、他の誰かが再びこの問題を抱えている場合に備えて私の解決策を共有したいと思います。

私はこのコードを持っていました:

public void finishAction() {
  onDestroy();
  finish();
}

「onDestroy();」という行を削除して問題を解決しました

public void finishAction() {
  finish();
}

私が最初のコードを書いた理由:「finish()」を実行すると、アクティビティが「onDestroy()」を呼び出すことを知っていますが、私はスレッドを使用しており、次のアクティビティを開始する前にすべてのスレッドが確実に破棄されるようにしたい、そして「finish()」は必ずしも即時ではないようです。多くの「ビットマップ」を処理/削減して大きな「ビットマップ」を表示する必要があり、アプリでメモリの使用を改善する作業をしています

次に、別のメソッドを使用してスレッドを強制終了し、このメソッドを "onDestroy();"から実行します。そして私がすべてのスレッドを殺す必要があると思うとき。

public void finishAction() {
  onDestroyThreads();
  finish();
}

0

私はこの問題を抱えていましたが、それはsetContentView(int id)自分ActivityonCreate


0

これは私をXamarinに夢中にさせました。

私はこれ自体がDrawerLayoutに実装されているFragment WITHINのTabLayoutのViewPager実装でこれに遭遇しました。

 - DrawerLayout
   - DrawerFragment
     - TabLayout
     - TabViewPager
       - TabViewPagerFragments

したがって、DrawerFragmentに次のコードを実装する必要があります。正しいFragmentManager-Pathを選択するように注意してください。2つの異なるFragmentManager参照がある可能性があるためです。

  1. Android.Support.V4.App.FragmentManager
  2. Android.App.FragmentManager

->使用するものを選択してください。ChildFragmentManagerを使用する場合は、クラス宣言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+"");
    }
}

0

このバグは最新のandroidxバージョンで修正されています。そして、有名な回避策は今クラッシュを引き起こします。今は必要ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.