cover

A Brief Analysis of RxActivityResult Principle

sorcererxw
Having recently started learning RxJava, I've been using some third-party extension libraries based on RxJava and found them to be quite magical, especially those libraries that can directly proxy Activity for data processing. However, due to laziness, I never really understood the underlying principles. Recently, I've been using RxActivityResult and found some minor issues that didn't quite work to my satisfaction. I raised some issues, but the author didn't provide a satisfactory response, so I decided to fork it, clone it down, try to make some changes myself, and take the opportunity to read through the source code.

Firstly, I would like to clarify that the following content only includes the basic principles of RxActivityResult and the source code that I have simplified. For more detailed content, you can check the source code in RxActivityResult.

Usage Method

First, let's mention the basic usage of RxActivityResult, which will be helpful for verification in the later analysis.

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);
                }
            }
        });

A simple step accomplishes the entire process of startActivityForResult().

Process and Principle

RxActivityResult initiates a proxy Activity - HolderActivity to act as a bridge for data interaction between two Activities. First, Activity A tells RxActivityResult the target Activity that needs to be launched, then RxActivityResult launches HolderActivity on its behalf. HolderActivity starts Activity B, then accepts the result returned by Activity B, and finally passes it through the callback method.

Source Code Analysis

First, let's introduce three basic classes, which will be used multiple times later.

/*
 * 最终返回给调用者的结果
 */
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;
                    }
                });
    }
}

Conclusion

In fact, upon analysis, it's not particularly profound. It's just that it's not very easy to understand the logic at the beginning.

Similar libraries include RxPermissions, which uses RxJava to simplify the process of permission application in Android 6.0+ systems. It likely also works by launching a transparent intermediary Activity to apply for permissions. After obtaining the application results, it informs the subscribers through a callback. The specific code will not be analyzed for now, but can be viewed in the source code repository.