2012年2月20日月曜日

サポートパッケージのFragmentでstartActivityForResultを使う場合の注意点

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

ついにFragmentに入門したわけですが、早速ハマったのでメモしておきます。サポートパッケージェ・・・。
※本エントリはandroid.support.v4.app.Fragmentに関する動作について書いています。android.app.Fragmentでは以下に書いている問題は発生しません。

FragmentでstartActivityForResultが使える


Fragmentって便利ですねー。特にActivityにベッタリ書いていた様な実装をFragmentに分けて色々捗らせる事が出来る点がとても助かります。で、Activityに書いていた処理をFragmentに集約する時に問題になるのがstartActivityForResultによって処理を委譲している部分です。

FragmentではstartActivityやstartActivityForResultやonActivityResultが用意されており、FragmentからActivityを起動したり、結果を受け取る事ができます。

という事でまぁ問題なくねーと思いがちですがしかし、FragmentのstartActivityForResultには罠があるんですねーーーー!


リクエストコードは下位16bitの範囲で


まず以下のコードをFragment内で実行してみます。なんの変哲もない、アドレス帳を起動して選択結果を受け取るだけのIntentです。

private final static int REQUEST_CODE = 0x11111;
public void pick() {
 Intent intent = new Intent(Intent.ACTION_PICK, 
  ContactsContract.Contacts.CONTENT_URI);
 startActivityForResult(intent, REQUEST_CODE);
}

し、死んだー!

Can only use lower 16 bits for requestCode


なにーー!
そうですFragmentではstartActivityForResultの第二引数に与えるリクエストコードを下位16bit以内に収める必要があります。
つまり0x0000〜0xffffまでの間の値にしろ、という事ですね。上記コードは"0x11111"だったのでダメだったんですね。

リクエストコードは下位16bitの範囲で。



onActivityResultが呼ばれないパターン


こういう罠にはまるのは僕くらいのものな気がしますが、サポートパッケージのFragmentのstartActivityForResultではonActivityResultが呼ばれないパターンがあります。
親となるActivity側がonActivityResultをオーバーライドしている場合に起きるのですが・・・。
コードを見てみます。問題無いようなあるような・・・。

親となるActivity側
@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data){
  switch (requestCode) {
  case REQUEST_CODE:
   //なにもしない
   break;
  case MOGE:
   //~処理~
   break;
  }
 }
Fragment側
@Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
  switch (requestCode) {
  case REQUEST_CODE:
   if(resultCode == Activity.RESULT_OK){
    Log.d(TAG, "okkkk!");
   }
   else{
    Log.d(TAG, "ooooops!");
   }
   break;
  }
 }

このコードの場合Fragment側のonActivityResultが呼ばれません。何故か?

super.onActivityResultを忘れているから!


そうです。親Activity側のsuper.onActivityResultを呼んでませんでした。
サポートパッケージでFragmentを使う場合はActivityではなくFragmentActivityを継承する必要があります。
このFragmentActivityのonActivityResultでFragmentに結果を渡しているのでsuper.onActivityResultを呼んであげないとFragment側にonActivityResultの呼び出しが行かないんですねー。

正しくは
@Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data){
  super.onActivityResult(requestCode, resultCode, data);
  switch (requestCode) {
  case REQUEST_CODE:
   //なにもしない
   break;
  case MOGE:
   //~処理~
   break;
  }
 }

問答無用でsuper.onActivityResult。



まとめ


コンパーチビリティの為のサポートパッケージですがなかなかどうして、大変ですねー。


0 件のコメント:

コメントを投稿