LoginSignup
16
14

More than 5 years have passed since last update.

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

Last updated at Posted at 2012-09-19

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

  1. startActivityForResult の第2引数にID(=任意の数値)を付けて呼び出す(ID は定数にするのが鉄則)
  2. 呼び出された Activity で setResult に戻り値を設定して finish()
  3. 呼び出し元 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。

参考

もっとちゃんとやるなら、下のような画面遷移フレームワークを導入した方が良さそう。
* AndroidアプリにStrutsのようなコントローラを導入し,画面制御させるサンプルコード(の試作品)- 主に言語とシステム開発に関して

16
14
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
14