画像をギャラリーから取ってこようと思ってstartActivityForResult使ってごにょごにょやってたらonActivityResultが呼ばれたり呼ばれなかったりしたので調べてみたことをメモ。
適当なActivityを起動して結果を貰いたいときにはstartActivityForResultを使う。
// 画像取得ボタンの実装 // Intentの帰りを受けるためにActivityクラス内で定義する @Override public void onClick(View v) { Intent intent = new Intent(); // 画像取得 intent.setAction(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, 0); }
受け取る方は受け取りたいActivityにonActivityResultを書いとくと読んでもらえる。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 0 && resultCode == RESULT_OK) { Uri uri = (Uri)data.getData(); String imgFileName = uri.getPath(); (略) } }
で、適当に作って適当に遊んでたらなんとなく動いたのでコードとか誰ともかぶらなさそうなのに変えようと思って変えてみた。
// 画像取得ボタンの実装 // Intentの帰りを受けるためにActivityクラス内で定義する @Override public void onClick(View v) { Intent intent = new Intent(); // 画像取得 intent.setAction(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, 0xDEADBEAF); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 0xDEADBEAF && resultCode == RESULT_OK) { Uri uri = (Uri)data.getData(); String imgFileName = uri.getPath(); (略) } }
でもこれだとonActivityResultが呼ばれない。なんでやねん。
で、差を見て理由がわからなかったので調べてみた。
まずstartActivityForResultのコードを見てみた。ソースはAOSPから拾ってきたICSのr1。
※markdownで書いてる都合上4スペースを1タブで変換してます。
Activity.java: startActivityForResult
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); }
上記の通りstartActivityForResultではsendActivityResultで結果を返す。
sendActivityResultが呼ばれるためにはexecStartActivityからActivityResultが返ってこないといけない。
execStartActivityの中身を見てみると、ActivityResultオブジェクトを返すところが以下のようになっている。
Instrumentation.java: execStartActivity
final ActivityMonitor am = mActivityMonitors.get(i); if (am.match(who, null, intent)) { am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null; } break; }
ActivityThreadが監視しているActivityMonitorの数だけ上記のコードが回されるんだけど細かいところはおいといて、returnのところを見るとリクエストコードが非負の整数でないと結果を返そうとしていない。
リクエストコードはstartActivityForResultで渡している値なので、試したコードを再掲すると。
// 画像取得ボタンの実装 // Intentの帰りを受けるためにActivityクラス内で定義する @Override public void onClick(View v) { Intent intent = new Intent(); // 画像取得 intent.setAction(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, 0xDEADBEAF); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 0xDEADBEAF && resultCode == RESULT_OK) { Uri uri = (Uri)data.getData(); String imgFileName = uri.getPath(); (略) } }
ばっちりリクエストコードが負の整数!
そりゃないぜセニョール! と思ってAndroid Developersを確認してみたら。。。
> Parameters
> intent The intent to start.
> requestCode If >= 0, this code will be returned in onActivityResult() when the activity exits.
ばっちり書いてあった(ノ∀`)アチャー
いつものことだけどドキュメントよく読めってことですね。サーセンwwwww