Activity からの戻り値をコールバックで受け取る

呼び出した Activity からの戻り値を受け取るには通常、

1. startActivityForResult の第2引数にID(=任意の数値)を付けて呼び出す(ID は定数にするのが鉄則)
2. 呼び出された Activity で setResult に戻り値を設定して finish()
3. 呼び出し元 Activity の onActivityResult が実行され、第1引数 requestCode で、どの呼び出しの戻り値かを判別。

とするけどスーパー面倒だし、Activity 呼び出しと受け取りが離れた場所になってしまうのでコードが読みづらい。

というわけで、こんなクラスを用意してみた。
**※Application クラスを使う方法に修正してみました。**

```Java: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);
		}
	}
}
```

```java: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();
	}
}
```
使う側はこんな感じ。

```java: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。

##参考
もっとちゃんとやるなら、下のような画面遷移フレームワークを導入した方が良さそう。
* [AndroidアプリにStrutsのようなコントローラを導入し，画面制御させるサンプルコード（の試作品）- 主に言語とシステム開発に関して](http://d.hatena.ne.jp/language_and_engineering/20120213/p1)