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

Posted gengqiquan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了告别onActivityResult ,用代理实现Rx方式获取startActivityForResult结果相关的知识,希望对你有一定的参考价值。

尊重他人的劳动成果,转载请标明出处:http://blog.csdn.net/gengqiquan/article/details/74331845, 本文出自:【gengqiquan的博客】

这个库已经废弃,请移步用代理获取startActivityForResult结果
这个库已经废弃,请移步用代理获取startActivityForResult结果
这个库已经废弃,请移步用代理获取startActivityForResult结果

一个多月没写博客了,实在是最近事情特别多。
昨天,在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技术问题,有兴趣的可以加下,大家一起进步。

以上是关于告别onActivityResult ,用代理实现Rx方式获取startActivityForResult结果的主要内容,如果未能解决你的问题,请参考以下文章

告别 LuaGoWasm 插件,是时候用低代码 API 网关了

onActivityResult 已弃用如何发送 startResolutionForResult

前端探索告别烂代码 用责任链模式封装网络请求

前端探索告别烂代码 用责任链模式封装网络请求

前端探索告别烂代码 用责任链模式封装网络请求

前端探索告别烂代码 用责任链模式封装网络请求