2012年4月26日木曜日

Android Fragment + ViewPager には id が必要

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

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

public class MainActivity2 extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewPager mViewPager = new ViewPager(this); setContentView(mViewPager); PagerAdapter mAdapter = new PagerAdapter(this); mViewPager.setAdapter(mAdapter); } class PagerAdapter extends FragmentPagerAdapter { private final Context mContext; public PagerAdapter(FragmentActivity activity) { super(activity.getSupportFragmentManager()); mContext = activity; } @Override public int getCount() { return 5; } @Override public Fragment getItem(int position) { Bundle args = new Bundle(); args.putInt("num", position * position); return Fragment.instantiate(mContext, SimpleFragment.class.getName(), args); } } }

public class SimpleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView tv = new TextView(inflater.getContext()); String message = "Message : " + getArguments().getInt("num"); tv.setText(message); return tv; } }

次のように 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)

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

712 void moveToState(Fragment f, int newState, int transit, int transitionStyle) { ... 722 if (f.mState < newState) { ... 737 switch (f.mState) { ... 781 case Fragment.CREATED: 782 if (newState > Fragment.CREATED) { 784 if (!f.mFromLayout) { 785 ViewGroup container = null; 786 if (f.mContainerId != 0) { 787 container = (ViewGroup)mActivity.findViewById(f.mContainerId); 788 if (container == null && !f.mRestored) { 789 throw new IllegalArgumentException("No view found for id 0x" 790 + Integer.toHexString(f.mContainerId) 791 + " for fragment " + f); 792 } 793 }

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

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

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

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewPager mViewPager = new ViewPager(this); setContentView(mViewPager); mViewPager.setId(100); PagerAdapter mAdapter = new PagerAdapter(this); mViewPager.setAdapter(mAdapter); }

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

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

<?xml version="1.0" encoding="utf-8"?> <resources> <item name="viewpager" type="id"/> </resources>

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewPager mViewPager = new ViewPager(this); setContentView(mViewPager); mViewPager.setId(R.id.viewpager); PagerAdapter mAdapter = new PagerAdapter(this); mViewPager.setAdapter(mAdapter); }

1 件のコメント: