告别onActivityResult ,用代理实现Rx方式获取startActivityForResult结果

来源:互联网 发布:淘宝直邮澳洲 编辑:程序博客网 时间:2024/06/05 18:27

尊重他人的劳动成果,转载请标明出处:http://blog.csdn.net/gengqiquan/article/details/74331845, 本文出自:【gengqiquan的博客】
一个多月没写博客了,实在是最近事情特别多。
昨天,在review 公司项目代码的时候发现onActivityResult方法真的好烦,太影响代码的阅读了,而且编写的时候也需要到处切code位置。于是就有了这篇博客和RxActivityResult 这个库。

大概的调用方式就是这样的

  RxActivityResult.with(MainActivity.this).putString("key", "笑一个")                        .startActivityWithResult(new Intent(MainActivity.this, SecondActivity.class))                        .subscribe(new Consumer<Intent>() {                            @Override                            public void accept(Intent intent) throws Exception {                                tv.setText(intent.getStringExtra("msg"));                            }                        });

源码大家直接到链接看好了,这篇博客主要是聊聊思路

要想完全告别onActivityResult(),有两种方案
1、使用进程注入的方式hook系统的activity数据发送,这种方案比较复杂,用到ndk知识,需要在源码下编译应用,不适合大部分人。
2、利用代理进行跳转事件转发代理和 onActivityResult()事件代理接收后再通知委托者。
这里我们用第二种,代理对象有两个供选择,一个是activity,每次startActivityForResult的时候打开的使我们的代理activity(ProxyActivity),然后由ProxyActivity进行转发intent,并在ProxyActivity里进行 onActivityResult()事件处理,然后通知委托者;所以我们需要在manifest进行注册,并且需要合理的管理activity的堆栈。
一个是利用Fragment,这就需要将Fragment加载到activity上,否则发起intent的时候会报 not attach activity 异常,再一个就是需要兼容v4和app两种情况,当然,如果大家的项目里的基类是固定的一种就不需要了。

下面我们来看看具体实现方式
首先构建一个请求容器对象,用来存放被转发的intent和请求识别码

public class Request  {    Intent intent;    int code;    public Request(Intent intent, int code) {        this.intent = intent;        this.code = code;    }}

再构建一个结果容器对象,用来存放onActivityResult返回的结果和请求识别码

public class Result {    Intent intent;    public Result(Intent intent, int code) {        this.intent = intent;        this.code = code;    }    int code;}

然后我们的返回结果是要以RxJava的方式传递给委托者的。这里我们可以参考rxbus的实现方式
构建一个subject

 static PublishSubject<Result> subject = PublishSubject.create();

然后我们需要把Fragment加载到Activity上,这就需要有一个界面控件ID和一个FragmentManager,FragmentManager我们可以从委托者获取,根据activity和fragmentActivity的不同决定获取不同的FragmentManager,这个控件ID怎么来呢?熟悉Android源码的同学可能就知道了,每个界面的根布局其实都是同一个系统ID(android.R.id.content)这个ID其实可以用来做很多事,比如透明状态栏时软键盘不顶起布局的时候可以用来强制位移布局,或者自己做伪分屏。

接下来就是创建一个代理fragment并且把请求委托给它

            final Request request = new Request(intent, intent.hashCode());                final V4Fragment v4Fragment = new V4Fragment();                v4Fragment.setRequest(request);                v4Transaction.replace(android.R.id.content, v4Fragment)                        .commitAllowingStateLoss();                v4Transaction = null;

这里的请求识别码我们直接通过求intent的hash值来得到。

在代理fragment里进行转发intent和转发返回结果操作

public class V4Fragment extends Fragment {    @Override    public void onActivityResult(int requestCode, int resultCode, Intent data) {        if (resultCode == Activity.RESULT_OK) {            if (request != null) {                RxActivityResult.post(new Result(data, request.code));            }            request = null;            this.getActivity().getSupportFragmentManager().beginTransaction().detach(this).commit();        }        super.onActivityResult(requestCode, resultCode, data);    }    Request request;    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        if (request != null) {            Intent intent = request.intent;            startActivityForResult(intent, 0);        }    }    public void setRequest(Request request) {        this.request = request;    }}

通过subject进行发送

  protected static void post(Result result) {        if (result.intent != null) {            subject.onNext(result);        } else {            subject.onError(new Exception("intent is null"));        }    }

根据请求识别码进行筛选

return subject.filter(new Predicate<Result>() {                @Override                public boolean test(Result result) throws Exception {                    return request.code == result.code;                }            }).map(new Function<Result, Intent>() {                @Override                public Intent apply(Result result) throws Exception {                    return result.intent;                }            });

这样就得到了委托者所需要的返回结果了。

完整的示例代码、源码及gradle依赖方式请看https://github.com/gengqiquan/RxActivityResult

有什么建议的可以留言喔

如果我的博客对您有帮助,请留言鼓励下或者点个赞吧!

我建了一个QQ群(群号:121606151),用于大家讨论交流Android技术问题,有兴趣的可以加下,大家一起进步。

阅读全文
2 0