2013-02-11 17 views
8

コンテキストにしようとしたとき:私はFragmentと3 InnerFragmentsActivityを持っています。 FragmentonDestroy()が呼び出されたときに、FragmentManagerから内側のフラグメントを削除したいと考えています。 onDestroy()のコードは次のとおりです。FragmentManager NullPointerExceptionがcommitAllowingStateLoss

問題:FragmentManagercommitAllowingStateLoss()が呼び出されたとき、おそらく、NullPointerExceptionをスローします。なぜか分からない。

@Override 
public void onDestroy() 
{ 
    super.onDestroy(); 
    if (getFragmentManager().findFragmentById(R.id.fragment_framelayout_left) != null) 
    { 
     FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); 
     fragmentTransaction.remove(mLeftFragment); 
     fragmentTransaction.commitAllowingStateLoss(); 
    } 
} 

スタックトレース:

02-11 12:15:14.162: E/AndroidRuntime(25911): FATAL EXCEPTION: main 
02-11 12:15:14.162: E/AndroidRuntime(25911): java.lang.NullPointerException 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1419) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:429) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.handleCallback(Handler.java:725) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Handler.dispatchMessage(Handler.java:92) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.os.Looper.loop(Looper.java:137) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at android.app.ActivityThread.main(ActivityThread.java:5039) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invokeNative(Native Method) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at java.lang.reflect.Method.invoke(Method.java:511) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
02-11 12:15:14.162: E/AndroidRuntime(25911): at dalvik.system.NativeStart.main(Native Method) 
+1

。 'InnerFragments'は' Fragment'に生きていますか?もしそうなら、 'Activity'の' FragmentManager'ではなく 'getChildFragmentManager()'を管理するべきだと思います。そうすれば、 'Fragment'が破棄されたときに、この余分なコードがなくても、' InnerFragments'の子どもたちも破壊されます。 –

+0

はい、内側の断片は断片の中に住んでいます(少なくともタブレット上)。電話機では、アクティビティ(アクティビティ1内のInnerFragment1、アクティビティ2内のInnerFragment2)内に存在します。だから私はそのコードを使っていたのです。アクティビティのgetChildFragmentManager()も使用できますか? LE:ばかげた質問、申し訳ありません。私は数時間後にあなたのアイデアを試し、それがどうなるか見てみましょう。 –

+1

'GetChildFragmentManager()'は 'Fragments'のみにあります。' Activities'は子 'FragmentManagers'にアクセスできないからです。しかし、 'Fragments'は' getFragmentManager() 'を呼び出して親の' Activity'の 'FragmentManager'にアクセスすることができます。 –

答えて

9

FragmentManagerActivityレベルですべてのFragmentsを管理し、そのライフサイクルはその親Activityに縛られます。子FragmentのマネージャはすべてレベルのFragmentsを管理しており、そのライフサイクルはその親のFragmentに結び付けられます。

携帯電話のアーキテクチャでは、InnerFragmentActivitygetFragmentManager()を追加してください。 Activityが正常終了(戻るボタン/ finish())した場合、FragmentManagerはあなたのためにInnerFragmentを破壊して解放します。

あなたのタブレットアーキテクチャには、FragmentInnerFragmentsを追加してください。最新のサポートライブラリでgetChildFragmentManager()を使用してください。 Fragmentが無効になると、FragmentManagerはあなたのためにInnerFragmentsを破壊し、解放します。

自分でFragmentsを解放して破壊する必要はありません。 ActivitiesFragmentsのライフサイクルイベントを記録することをお勧めします。ライフサイクルイベントの状態を確認し、正しい動作を確認することができます。

+0

どうもありがとう。これで解決しました。 1つのわずかな問題。ChildFragmentManagerを使用すると、子フラグメントに対してsetRetainInstance(true)を実行できません。回避策はありますか?それとも、なぜこのように振る舞うべきですか? –

+1

'setRetainInstance(true)'を使うことは、実際には既に回避策です。 Googleが提案するアプローチは、変数onSaveInstanceState()に変数の状態を保存し、それを 'onCreate'と' onCreateView'に復元することです。 OSはメモリが不足していて、「フラグメント」や「アクティビティ」を破壊する必要があるため、現在の状態を保存してユーザーに表示されるように復元する必要があります彼らが戻るときに何も変わっていないからです。 http://developer.android.com/training/basics/activity-lifecycle/recreating.htmlの状態をGoogleに保存することをおすすめします。 –

+1

そして 'setRetainInstance(true)'についてもう少し詳しく知りたいです - http://stackoverflow.com/questions/11182180/understanding-fragments-setretaininstanceboolean –

1

にNullPointerExceptionが活動のハンドラは、FragmentManagerから設定されていないという事実によって引き起こされるが、そのクラッシュを防ぐことができます「ソリューション」は以下の通りです:私は完全にあなたのアーキテクチャを以下のいないよ

public void onDestroy(){ 
     super.onDestroy(); 
     try { 
      Field mActivityField = getFragmentManager().getClass().getDeclaredField("mActivity"); 
      mActivityField.setAccessible(true); 
      mActivityField.set(getFragmentManager(), this); 

      Field mPendingActionsField = getFragmentManager().getClass().getDeclaredField("mPendingActions"); 
      mPendingActionsField.setAccessible(true); 
      mPendingActionsField.set(getFragmentManager(), null); 


      Field f = Activity.class.getDeclaredField("mHandler"); 
      f.setAccessible(true); 
      Handler handler = (Handler) f.get(this); 
      handler.close(); 
     } catch (Throwable e) { 

     } 
}