2013年4月25日木曜日

Fragment in Fragment 時の注意点

Android 4.2 で Fragment in Fragment 用の API が用意されました。
NestedFragments : Android 4.2

また、Support Library でも同様の機能が提供されています。

今回、この API を使ってちょっとはまったのでメモしておきます。

構成としては

Activity の ActionBar の
Tab
 |
Fragment(A) の
ViewPager
 |
Fragment(B)

のようになっています。

Fragment(A)では、getChildFragmentManager() をつかって素直に ViewPager に Adapter をセットしているだけです。

Fragment(A)
  1. public class TabFragment3 extends SherlockFragment {  
  2.   
  3.     ViewPager mPager;  
  4.   
  5.     @Override  
  6.     public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {  
  7.         View v = inflater.inflate(R.layout.fragment_pager, parent, false);  
  8.         mPager = (ViewPager) v.findViewById(R.id.pager);  
  9.         return v;  
  10.     }  
  11.   
  12.     @Override  
  13.     public void onActivityCreated(Bundle savedInstanceState) {  
  14.         super.onActivityCreated(savedInstanceState);  
  15.         MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager());  
  16.         mPager.setAdapter(adapter);  
  17.     }  
  18.   
  19.     public class MyPagerAdapter extends FragmentPagerAdapter {  
  20.   
  21.         public MyPagerAdapter(FragmentManager fm) {  
  22.             super(fm);  
  23.         }  
  24.   
  25.         @Override  
  26.         public Fragment getItem(int position) {  
  27.             PageFragment fragment = new PageFragment();  
  28.             return fragment;  
  29.         }  
  30.   
  31.         @Override  
  32.         public int getCount() {  
  33.             return 3;  
  34.         }  
  35.     }  
  36. }  
Activity では、ActionBar に普通に Tab をセットしています。
  1. public class MainActivity extends SherlockFragmentActivity implements TabListener {  
  2.   
  3.     TabFragment1 mTabFragment1;  
  4.     TabFragment2 mTabFragment2;  
  5.     TabFragment3 mTabFragment3;  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.   
  11.         mTabFragment1 = new TabFragment1();  
  12.         mTabFragment2 = new TabFragment2();  
  13.         mTabFragment3 = new TabFragment3();  
  14.   
  15.         ActionBar actionBar = getSupportActionBar();  
  16.         actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);  
  17.         actionBar.addTab(actionBar.newTab()  
  18.                                   .setText(R.string.tab1)  
  19.                                   .setTabListener(this));  
  20.         actionBar.addTab(actionBar.newTab()  
  21.                                   .setText(R.string.tab2)  
  22.                                   .setTabListener(this));  
  23.         actionBar.addTab(actionBar.newTab()  
  24.                                   .setText(R.string.tab3)  
  25.                                   .setTabListener(this));  
  26.     }  
  27.   
  28.     @Override  
  29.     public void onTabSelected(Tab tab, FragmentTransaction ft) {  
  30.         int position = tab.getPosition();  
  31.         switch (position) {  
  32.             case 0:  
  33.                 ft.replace(android.R.id.content, mTabFragment1);  
  34.                 break;  
  35.             case 1:  
  36.                 ft.replace(android.R.id.content, mTabFragment2);  
  37.                 break;  
  38.             case 2:  
  39.                 ft.replace(android.R.id.content, mTabFragment3);  
  40.                 break;  
  41.         }  
  42.     }  
  43.   
  44.     @Override  
  45.     public void onTabUnselected(Tab tab, FragmentTransaction ft) {  
  46.     }  
  47.   
  48.     @Override  
  49.     public void onTabReselected(Tab tab, FragmentTransaction ft) {  
  50.     }  
  51. }  
こうすると、Fragment(A)のタブを開いて、一旦別のタブを開いてから、戻ると落ちるんです!
ViewPager に Adapter をセットしているところで

04-25 10:46:44.949: E/AndroidRuntime(21011): FATAL EXCEPTION: main
04-25 10:46:44.949: E/AndroidRuntime(21011): java.lang.IllegalStateException: Activity has been destroyed

とか言われます。

onTabSelected() で replace する Fragment(A) のインスタンスを毎回作り直すようにしたら落ちなくなりました!
  1. public class MainActivity extends SherlockFragmentActivity implements TabListener {  
  2.   
  3.     ...  
  4.   
  5.     @Override  
  6.     public void onTabSelected(Tab tab, FragmentTransaction ft) {  
  7.         int position = tab.getPosition();  
  8.         switch (position) {  
  9.             case 0:  
  10.                 ft.replace(android.R.id.content, mTabFragment1);  
  11.                 break;  
  12.             case 1:  
  13.                 ft.replace(android.R.id.content, mTabFragment2);  
  14.                 break;  
  15.             case 2:  
  16.                 mTabFragment3 = new TabFragment3();  
  17.                 ft.replace(android.R.id.content, mTabFragment3);  
  18.                 break;  
  19.         }  
  20.     }  
  21. }  
はまったわー。。。。