美文网首页
Rxbus结合dagger2作用域实现局部单例(资源自动回收和事

Rxbus结合dagger2作用域实现局部单例(资源自动回收和事

作者: Lightofrain | 来源:发表于2017-05-24 21:50 被阅读0次

    原由

    之前使用Rxjava2实现的单例模式的Rxbus来进行组件通信

    现在有两个问题不好实现:

    • 在不同的Activity中同时post出两个相同的Class类型,只想在当前Activity中接收该类型事件
    • 实现订阅事件后产生的Disposable统一管理回收(使用者不用考虑回收问题,在当前Activity产生的Disposable自动在onDestroy()后被回收)

    之后是为什么会产生上面两种需求的场景

    最近在使用MVP模式封装Retrofit网络访问模块时,需要从Model层回调给Presenter层再回调给View层,虽然解耦很强,但作为喜欢偷懒的程序员,总觉得这么写很费劲.
    于是乎,就思考如何简化代码而又不影响解耦程度

    经过一天的思考和设计,得到以下方案:

    • 去除Presenter层(使用Rxbus代替其功能)
    • View层接口去除,接收事件改造成订阅事件
    • Model层功能不变,回调数据给Presenter层改为发送事件给订阅者(View层)

    仔细想了想,发现这个方案不仅没有增加耦合度,还精简了一半的代码,而其中最重要的就是通过Rxbus来进行事件的订阅和发送

    注:这种方式实现MVP模型的方式放在下一篇文章来说,这篇文章主要讲一讲结合dagger2作用域实现局部单例

    3501495-a758dc63cd78364a.png

    备注:图画的有点丑.别介意!

    实现

    首先写出dagger2的Component和Module

    //这里使用单例域
    @Singleton
    @Component(modules = AppModule.class)
    public interface AppComponent {
        //这里暴露子组件
        BaseComponent baseComponent(BaseModule baseModule);
    }
    
    
    @Singleton
    @Module
    public class AppModule {
        private App mApp;
        public AppModule(App app) {
            mApp = app;
        }
    
        /**
         * 将App提供出去
         * @return
         */
        @Singleton
        @Provides
        App providerApp() {
            return mApp;
        }
    }
    

    以上是单例域的Component域Module,在App中注册,因应用只有一个Application,所以在这个域中提供的@Singleton注解的对象都将只有一份(也就是单例效果)

    之后是Activity域的dagger组件

    //这里是针对BaseActivity,所有继承BaseActivity的Activity都在BaseScope域下,但这些子类之间却互不影响,各自维持一个BaseScope
    //因为每个子类都会在父类的onCreate()方法中创建一个BaseComponent,虽然都在BaseScope下,但却被两个不同的BaseComponent对象分别管理
    //所以BaseModule所提供的对象都只在当前Activity中保持单例
    @BaseScope
    @Subcomponent(modules = BaseModule.class)
    public interface BaseComponent {
        void inject(MainActivity activity);
    
        void inject(Main2Activity activity);
    }
    
    
    @BaseScope
    @Module
    public class BaseModule {
        private Activity mActivity;
        private CompositeDisposable mDisposable = new CompositeDisposable();
    
        public BaseModule(Activity activity) {
            mActivity = activity;
        }
    
        @BaseScope
        @Provides
        Activity providerActivity() {
            return mActivity;
        }
    
        @BaseScope
        @Provides
        Context providerContext() {
            return mActivity;
        }
    
        /**
         * CompositeDisposable,这里使用了BaseScope域,则在此域中的mDisposable对象只有一份(也就是局部单例)
         * @return
         */
        @BaseScope
        @Provides
        CompositeDisposable providerDisposable() {
            return mDisposable;
        }
    }
    
    

    dagger的组件都搭建完毕,此时就该正主上场了
    在这里将实现一个非单例的Rxbus,通过dagger作用域来实现局部单例,这也就会使发送的事件只会在局部被接收,并通过事件管理器来自动回收资源

    //使Rxbus的作用域为Activity域,保证其在该域中,也就是Activity中保证单例(本例中作用域被限制在了Activity中,可根据情况更改)
    @ActivityScope
    public class RxBus {
        private final FlowableProcessor<Object> mBus;
        //将Rxbus注入
        @Inject
        public RxBus() {
            //调用toSerialized()方法,保证线程安全
            mBus = PublishProcessor.create().toSerialized();
        }
    
        /**
         * 发送消息
         * @param o
         */
        public void post(Object o) {
            new SerializedSubscriber<>(mBus).onNext(o);
        }
    
        /**
         * 确定接收消息的类型
         * @param aClass
         * @param <T>
         * @return
         */
        public <T> Flowable<T> toFlowable(Class<T> aClass) {
            return mBus.ofType(aClass);
        }
    
        /**
         * 判断是否有订阅者
         * @return
         */
        public boolean hasSubscribers() {
            return mBus.hasSubscribers();
        }
    
    }
    

    然后是事件管理器和事件包裹类

    @BaseScope
    public class SubstribeManager {
        @Inject
        RxBus mRxBus;
        //这里得到的CompositeDisposable与Activity中的是同一个对象
        @Inject
        CompositeDisposable mDisposable;
        @Inject
        public SubstribeManager() {
        }
    
        /**
         * 发送事件
         * @param o
         */
        public void post(Object o) {
            mRxBus.post(o);
        }
    
        /**
         * 订阅事件,返回包裹类,方便同一回收Disposable
         * @param aClass
         * @param <T>
         * @return
         */
        public <T> FlowableWrap<T> subscribeResult(Class<T> aClass) {
            return new FlowableWrap<>(mRxBus.toFlowable(aClass),mDisposable);
        }
    
    }
    
    
    public class FlowableWrap<T> {
        private Flowable<T> mFlowable;
        private CompositeDisposable mDisposable;
    
        public FlowableWrap(Flowable<T> flowable, CompositeDisposable disposable) {
            mFlowable = flowable;
            mDisposable = disposable;
        }
    
        /**
         * 订阅事件,与Rxjava一致,自动添加事件到CompositeDisposable中,方便回收
         */
        public void subscribe(final Consumer<T> consumer) {
            mDisposable.add(mFlowable.subscribe(new Consumer<T>() {
                @Override
                public void accept(@NonNull T t) throws Exception {
                    consumer.accept(t);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(@NonNull Throwable throwable) throws Exception {
                    //do something for error
                }
            }));
        }
    
        /**
         * 订阅事件,与Rxjava一致,自动添加事件到CompositeDisposable中,方便回收
         * 可自己处理异常
         */
        public void subscribe(final Consumer<T> consumer, final Consumer<? super Throwable> error) {
            mDisposable.add(mFlowable.subscribe(new Consumer<T>() {
                @Override
                public void accept(@NonNull T t) throws Exception {
                    consumer.accept(t);
                }
            }, new Consumer<Throwable>() {
                @Override
                public void accept(@NonNull Throwable throwable) throws Exception {
                    error.accept(throwable);
                }
            }));
        }
    }
    

    然后开始使用!!!
    为了体现出效果,用RecyclerView创建出一个列表,当点击item时发送item的position
    在Activity中订阅Integer类型的事件,接收到事件后把position 吐司出来

    adapter代码

    @BaseScope
    public class MainRvAdapter extends RecyclerView.Adapter<MainRvAdapter.MyViewHolder> {
        @Inject
        SubstribeManager mManager;
        //将Adapter也注入
        @Inject
        public MainRvAdapter() {
        }
    
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            TextView tv = new TextView(parent.getContext());
            return new MyViewHolder(tv);
        }
    
        @Override
        public void onBindViewHolder(MyViewHolder holder, final int position) {
            TextView tv = (TextView) holder.itemView;
            tv.setText("随意的布局,随意的数据"+position);
            tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //发送事件,类型为Integer的position
                    mManager.post(position);
                }
            });
        }
    
        @Override
        public int getItemCount() {
            return 100;
        }
    
        class MyViewHolder extends RecyclerView.ViewHolder {
            public MyViewHolder(View itemView) {
                super(itemView);
            }
        }
    }
    
    

    再来看看BaseActivity代码

    @BaseScope
    public abstract class BaseActivity extends AppCompatActivity{
        //CompositeDisposable在BaseModule中被提供,并且作用域是BaseScope,所以在该域内该对象都只有一份
        @Inject
        CompositeDisposable mDisposable;
        @Inject
        SubstribeManager mManager;
        private BaseComponent mBaseComponent;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //通过父组件AppComponent来注册BaseComponent
            mBaseComponent = ((App) getApplication()).getAppComponent().baseComponent(new BaseModule(this));
            inject();
        }
    
        /**
         * 得到BaseComponent
         * @return
         */
        protected BaseComponent getBaseComponent() {
            return mBaseComponent;
        }
    
        /**
         * 需要子类进行inject
         */
        protected abstract void  inject();
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //回收CompositeDisposable,因整个BaseScope域都用的同一个,所以能把所有产生的Disposable回收
            mDisposable.dispose();
        }
    }
    

    主要的Activity代码

    public class MainActivity extends BaseActivity {
        @Inject
        MainRvAdapter mAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
            rv.setLayoutManager(new LinearLayoutManager(this));
            rv.setAdapter(mAdapter);
            Log.d("MainActivity", mDisposable+"");
            findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //这里可以尝试提前dispose(),就会发现之前订阅的事件已经接收不到了,也验证了事件被自动添加到CompositeDisposable中了
    //              mDisposable.dispose();
                    startActivity(new Intent(MainActivity.this,Main2Activity.class));
                }
            });
            subtribeData();
        }
    
        @Override
        protected void inject() {
            getBaseComponent().inject(this);
        }
    
        /**
         * 订阅Integer类型事件
         */
        private void subtribeData() {
            //这里不需要再考虑回收问题
            mManager.subscribeResult(Integer.class).subscribe(new Consumer<Integer>() {
                @Override
                public void accept(@NonNull Integer integer) throws Exception {
                    Toast.makeText(MainActivity.this, "被点到的item为: "+integer, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    

    结果图


    Screenshot_2017-05-24-21-25-17.png

    这里验证一下两个Activity中维持的事件管理器(SubstribeManager)是否是同一个

    image.png

    看截图就会发现不同的Activity之间提供的处于BaseScope域中的对象不相同,所以Activity之间相互独立,发送的事件也不会"窜门"!

    最后需要验证的就是Disposable是否会被自动回收

    QQ截图20170526121332.png

    在点击事件中提前把CompositeDisposable集合回收了,
    就会发现再也收不到之前订阅的事件了,这也就验证了Disposable被自动添加到集合中了,并在onDestroy()时,通过父类的实现,而被回收了

    本篇文章是关于Rxbus组件内(局部)通信的简单使用,之后的文章会带来更加有意思的用法!

    **
    github:https://github.com/lightofrain/LocalRxbus.git
    **

    相关文章

      网友评论

          本文标题:Rxbus结合dagger2作用域实现局部单例(资源自动回收和事

          本文链接:https://www.haomeiwen.com/subject/xhwoxxtx.html