cover

RxActivityResult 原理の簡単な分析

sorcererxw
RxJavaを学び始めて間もないので、RxJavaを基にしたサードパーティの拡張ライブラリを使っていて、本当に魔法のようだと感じています。特に、Activityを代理してデータ処理を直接行うライブラリは素晴らしいですが、怠け者なので、その原理についてはこれまで理解していませんでした。しかし最近、RxActivityResultを使ってみて、いくつかの小さな点がスムーズでないことに気づき、issueを提出しましたが、作者からは満足のいく返答が得られませんでした。そこで、思い切ってforkして、cloneしてみて自分で修正を試みるとともに、ソースコードを読んでみることにしました。

まず始めに、以下の内容はRxActivityResultの基本原理と私が簡略化したソースコードのみを含んでいます。具体的な内容はRxActivityResultのリポジトリでソースコードをご覧ください。

使用方法

RxActivityResultの基本的な使用方法について先に触れておきます。これにより、後での分析で検証が容易になります。

RxActivityResult.on(mActivityA)
        .startIntent(new Intent(mActivityA, ActivityB.class)
                .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) /*移除Activity启动时的动画*/)
        .subscribe(new Action1<Result>() {
            @Override
            public void call(Result result) {
                if (result.getData() != null) {
                    result.data().getIntExtra("key", 0);
                }
            }
        });

シンプルな一手間でstartActivityForResult()の全プロセスを実現します。

プロセスと原理

RxActivityResultは、HolderActivityという代理Activityを起動して、二つのActivity間のデータ交換の橋渡しを行います。まずActivity Aで、RxActivityResultに起動したい目的のActivityを伝え、その後RxActivityResultが代わりにHolderActivityを起動します。HolderActivityがActivity Bを起動し、Activity Bから返されたresultを受け取り、その後コールバックメソッドを通じて

ソースコード分析

まずは基礎となる3つのクラスを紹介します。これらは後に何度も使用されます。

/*
 * 最终返回给调用者的结果
 */
class Result<T> {
    T mActivity;
    int mResultCode;
    Intent mData;
}

/*
 * 提供给HolderActivity 在获取到数据后来调用的接口
 */
interface OnResult {
    void response(int resultCode, @Nullable Intent data);
}

/*
 * 打包了启动B Activity 的intent 和回调接口的类
 * 到时候会中启动HolderActivity 之前保存到HolderActivity 当中
 */
class Request {
    Intent mIntent;
    OnResult mOnResult;
}
public class RxActivityResult {
    // ActivitiesLifecycleCallbacks 和整个流程关系不大, 用处就是注册中application 中,
    // 来获得当前应用的最顶层 Activity, 感兴趣的可以在后面看到
    private static ActivitiesLifecycleCallbacks mActivitiesLifecycleCallbacks;

    public static void register(final Application application) {
        mActivitiesLifecycleCallbacks = new ActivitiesLifecycleCallbacks(application);
    }

    // 获取一个RxActivityResult的Builder
    public static <T extends Activity> Builder<T> on(T activity) {
        return new Builder<>(activity);
    }

    // RxActivityResult核心
    public static class Builder<T extends Activity> {
        final Class mClass;
        // 一个Subject, 用于提供给外界订阅
        final PublishSubject<Result<T>> mSubject = PublishSubject.create();

        public Builder(T activity) {
            if (mActivitiesLifecycleCallbacks == null) {
                throw new IllegalStateException("not registered");
            }

            mClass = activity.getClass();
        }

        // 提供给外界来启动intent, 本质上是将intent 打包在Request 当中,
        // 启动HolderActivity 并将Request 提供给HolderActivity
        public Observable<Result<T>> startIntent(Intent intent) {
            return startHolderActivity(new Request(intent));
        }

        private Observable<Result<T>> startHolderActivity(Request request) {
            request.setOnResult(mOnResultActivity);
            HolderActivity.setRequest(request);
            mActivitiesLifecycleCallbacks.getLiveActivity() // 获取当前应用顶层的Activity
                .subscribe(new Action1<Activity>() {
                    @Override
                    public void call(Activity activity) {
                        activity.startActivity(new Intent(activity, HolderActivity.class)
                                .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION));
                    }
                });

            return mSubject.asObservable();
        }

        // 一个回调接口, 当HolderActivity 接受到数据后会调用这个接口
        private OnResult mOnResultActivity = new OnResult() {
            @Override
            public void response(int resultCode, @Nullable Intent data) {
                if (mActivitiesLifecycleCallbacks.getLiveActivityOrNull() == null
                        || mActivitiesLifecycleCallbacks.getLiveActivityOrNull()
                        .getClass() != mClass) {
                    return;
                }
                Activity activity = mActivitiesLifecycleCallbacks.getLiveActivityOrNull();
                // 通知subject 的订阅者, 将Activity Result 传递过去
                mSubject.onNext(new Result<>((T) activity, resultCode, data));
                // subject 的使命已完成, 同时这一次RxActivityResult 的流程结束
                mSubject.onCompleted();
            }
        };
    }
}
/*
 * HolderActivity, 作为中间的桥梁来传递数据
 */
public class HolderActivity extends Activity {
    private static Request mRequest;

    // 被 A Activity调用, 用于存储回调
    public static void setRequest(Request request) {
        mRequest = request;
    }

    private int mResultCode;
    private Intent mData;
    private OnResult mOnResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 验证回调是否存在
        if (mRequest == null) {
            finish();
            return;
        }

        mOnResult = mRequest.getOnResult();

        // 确保是第一次打开, 防止B Activity被多次打开
        if (savedInstanceState != null) {
            return;
        }

        // 打开B Activity
        startActivityForResult(mRequest.getIntent(), 0);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // 接收到结果, 直接关闭这个界面
        mResultCode = resultCode;
        mData = data;
        finish();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // 在被结束前执行回调方法
        if (mOnResult != null) {
            mOnResult.response(mResultCode, mData);
        }
    }
}
public class ActivitiesLifecycleCallbacks {
    final Application mApplication;
    volatile Activity mLiveActivityOrNull;
    Application.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;

    public ActivitiesLifecycleCallbacks(Application application) {
        mApplication = application;
        registerActivityLiftcycle();
    }

    private void registerActivityLiftcycle() {
        if (mActivityLifecycleCallbacks != null) {
            mApplication.unregisterActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
        }
        mActivityLifecycleCallbacks = new SimpleActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {
                mLiveActivityOrNull = activity;
            }

            @Override
            public void onActivityResumed(Activity activity) {
                mLiveActivityOrNull = activity;
            }

            @Override
            public void onActivityPaused(Activity activity) {
                mLiveActivityOrNull = null;
            }
        };

        mApplication.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
    }

    Activity getLiveActivityOrNull() {
        return mLiveActivityOrNull;
    }

    volatile boolean mEmitted = false;

    Observable<Activity> getLiveActivity() {
        mEmitted = false;
        return Observable.interval(50, 50, TimeUnit.MILLISECONDS)
                .map(new Func1<Long, Activity>() {
                    @Override
                    public Activity call(Long aLong) {
                        return mLiveActivityOrNull;
                    }
                })
                .takeWhile(new Func1<Activity, Boolean>() {
                    @Override
                    public Boolean call(Activity activity) {
                        boolean continueEmitting = !mEmitted;
                        mEmitted = activity != null;
                        return continueEmitting;
                    }
                })
                .filter(new Func1<Activity, Boolean>() {
                    @Override
                    public Boolean call(Activity activity) {
                        return activity != null;
                    }
                });
    }
}

結語

実際に分析してみると、特に深遠なことはなく、最初に理解しようとするときに、そのロジックをすぐに整理するのが簡単ではないことがわかります。

同様のライブラリには、RxPermissionsがあります。これはRxJavaを使用して、Android 6.0+システムでの権限要求プロセスを簡素化するものです。透明な中間Activityを起動し、そのActivityで権限を要求し、要求結果を得た後、コールバックを通じて購読者に通知します。具体的なコードはここでは分析しませんが、ソースコードリポジトリで確認することができます。