2012年4月26日木曜日

Android Fragment + ViewPager には id が必要

ViewPager を Fragment と一緒に使うときの注意として ViewPager には id がセットされていなければならない、というものがあります。

例えば、次の用に XML レイアウトを使わないで ViewPager を画面に追加した場合、アプリが強制終了します。

  1. public class MainActivity2 extends FragmentActivity {  
  2.   
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.   
  7.         ViewPager mViewPager = new ViewPager(this);  
  8.         setContentView(mViewPager);  
  9.   
  10.         PagerAdapter mAdapter = new PagerAdapter(this);  
  11.         mViewPager.setAdapter(mAdapter);  
  12.   
  13.     }  
  14.   
  15.     class PagerAdapter extends FragmentPagerAdapter {  
  16.   
  17.         private final Context mContext;  
  18.   
  19.         public PagerAdapter(FragmentActivity activity) {  
  20.             super(activity.getSupportFragmentManager());  
  21.             mContext = activity;  
  22.         }  
  23.   
  24.         @Override  
  25.         public int getCount() {  
  26.             return 5;  
  27.         }  
  28.   
  29.         @Override  
  30.         public Fragment getItem(int position) {  
  31.             Bundle args = new Bundle();  
  32.             args.putInt("num", position * position);  
  33.             return Fragment.instantiate(mContext,  
  34.                     SimpleFragment.class.getName(), args);  
  35.         }  
  36.     }  
  37. }  


  1. public class SimpleFragment extends Fragment {  
  2.   
  3.     @Override  
  4.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  5.         TextView tv = new TextView(inflater.getContext());  
  6.         String message = "Message : " + getArguments().getInt("num");  
  7.         tv.setText(message);  
  8.         return tv;  
  9.     }      
  10. }  


次のように IllegalArgumentException が投げられるのですが、

04-26 20:56:16.739: E/AndroidRuntime(28770): java.lang.IllegalArgumentException: No view found for id 0xffffffff for fragment SimpleFragment{4183dd90 #0 id=0xffffffff android:switcher:-1:0}
04-26 20:56:16.739: E/AndroidRuntime(28770): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:864)

ここの部分のコードを見ると次のようになっています。

  1. 712     void moveToState(Fragment f, int newState, int transit, int transitionStyle) {  
  2.   
  3. 722         if (f.mState < newState) {  
  4.   
  5. 737             switch (f.mState) {  
  6.   
  7. 781                 case Fragment.CREATED:  
  8. 782                     if (newState > Fragment.CREATED) {  
  9. 784                         if (!f.mFromLayout) {  
  10. 785                             ViewGroup container = null;  
  11. 786                             if (f.mContainerId != 0) {  
  12. 787                                 container = (ViewGroup)mActivity.findViewById(f.mContainerId);  
  13. 788                                 if (container == null && !f.mRestored) {  
  14. 789                                     throw new IllegalArgumentException("No view found for id 0x"  
  15. 790                                             + Integer.toHexString(f.mContainerId)  
  16. 791                                             + " for fragment " + f);  
  17. 792                                 }  
  18. 793                             }  


これをみると、 Fragment (この場合は ViewPager の中身に Fragment のこと)がレイアウトから生成されていない場合で、Fragment の コンテナの Id が 0 でない場合に、その Id に対応する View が見つからないと上記のエラーの IllegalArgumentException が発行されることがわかります。

上記のエラーメッセージでは Fragment のコンテナの Id として 0 ではなく、0xffffffff が渡されていることがわかります。

ViewPager に明示的に Id をセットするとこのエラーはなくなります。

  1. @Override  
  2. public void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.   
  5.     ViewPager mViewPager = new ViewPager(this);  
  6.     setContentView(mViewPager);  
  7.     mViewPager.setId(100);  
  8.   
  9.     PagerAdapter mAdapter = new PagerAdapter(this);  
  10.     mViewPager.setAdapter(mAdapter);  
  11. }  


ここでは適当に 100 としましたが、こうするのは良くないです。

次のように res で id を定義し、それを使います。

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <item name="viewpager" type="id"/>  
  5.   
  6. </resources>  


  1. @Override  
  2. public void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.   
  5.     ViewPager mViewPager = new ViewPager(this);  
  6.     setContentView(mViewPager);  
  7.     mViewPager.setId(R.id.viewpager);  
  8.   
  9.     PagerAdapter mAdapter = new PagerAdapter(this);  
  10.     mViewPager.setAdapter(mAdapter);  
  11. }  

1 件のコメント: