呼び出した Activity からの戻り値を受け取るには通常、
- startActivityForResult の第2引数にID(=任意の数値)を付けて呼び出す(ID は定数にするのが鉄則)
- 呼び出された Activity で setResult に戻り値を設定して finish()
- 呼び出し元 Activity の onActivityResult が実行され、第1引数 requestCode で、どの呼び出しの戻り値かを判別。
とするけどスーパー面倒だし、Activity 呼び出しと受け取りが離れた場所になってしまうのでコードが読みづらい。
というわけで、こんなクラスを用意してみた。
※Application クラスを使う方法に修正してみました。
BaseActivity.java
/**
* startActivityForResult と onActivityResult をつなぐための Base クラス
*/
public abstract class BaseActivity extends Activity {
/** Activity からのコールバックインターフェース */
public interface OnActivityResultCallback {
void onResult(int resultCode, Intent data);
}
/**
* Activity を呼び出す。第2引数で呼び出し先からの戻り値を受け取る。
*/
public void startActivityForCallback(Intent intent, OnActivityResultCallback callback) {
MyApplication app = (MyApplication)this.getApplication();
Integer id = app.getActivityCallbackNum();
app.putActivityCallback(id, callback);
startActivityForResult(intent, id);
}
/**
* Activity からの戻りを受け取り、callbacks 内のコールバックを呼び出す。
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// MyApplication._callbacks に requestCode があったら、そのコールバックを呼び出す。
MyApplication app = (MyApplication)this.getApplication();
OnActivityResultCallback callback = app.getActivityCallback(requestCode);
if (callback != null) {
callback.onResult(resultCode, data);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
MyApplication.java
/**
* Activity いつでも破棄される可能性があるので Application で callbacks を保持
* 但し確実ではない via http://stackoverflow.com/questions/4585627/android-application-class-lifecycle
*
* AndroidManifest.xml への設定を忘れずに
*/
public final class MyApplication extends Application {
private SparseArray<OnActivityResultCallback> _activityCallbacks
= new SparseArray<OnActivityResultCallback>();
public OnActivityResultCallback getActivityCallback(int requestCode) {
if (_activityCallbacks.indexOfKey(requestCode) >= 0) {
OnActivityResultCallback found = _activityCallbacks.get(requestCode);
_activityCallbacks.remove(requestCode);
return found;
} else {
return null;
}
}
public void putActivityCallback(int requestCode, OnActivityResultCallback callback) {
_activityCallbacks.put(requestCode, callback);
}
public int getActivityCallbackNum() {
return _activityCallbacks.size();
}
}
使う側はこんな感じ。
MainActivity.java
public class MainActivity extends BaseActivity {
public void button1_click(View view) {
Intent intent = new Intent(this, SecondActivity.class);
// コールバック付きで Activity 呼び出し
startActivityForCallback(intent, new OnActivityResultCallback() {
// ここで値を受け取れる
public void onResult(int resultCode, Intent data) {
Log.d("MainActivity", "onActivityResult - "
+ data.getStringExtra("result"));
}
});
}
}
これで定数とか switch とかなくなってスッキリした。なにより「画面を呼び出したところ」で戻り値の処理が書けるのは嬉しい。
_callbacks
は連番ならただの List
でよさげだが、なんか怖いので Map にした。(始め Map<Integer, OnActivityResultCallback>
を使っていたら SparseArray
の方が速いよ、と Lint に怒られたorz)
Dialog
の呼び出し〜受け取りもなんとかしたいYO。
##参考
もっとちゃんとやるなら、下のような画面遷移フレームワークを導入した方が良さそう。