画像をギャラリーから取ってこようと思って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