RxJava实现Android MVP

前言:MVP是什么我就不讲了,如果需要的可以去百度查查资料。

RxJava是观察者模式的一种实现,观察者为Consumer或者Subscriber 被观察者为Flowable

我们大致理一理,实现一个Present需要什么内容:

  • 1.基本的,Present要得到Activity的实例对象,它们是一对一的关系。

  • 2.首先,Present肯定是被观察者,他要处理完事件后返回结果给观察它的人。所以他要实现Flowable中具体的方法。

  • 3.他要有接受事物处理的对象,也就是函数的参数,然后根据参数来进行处理和返回结果

  • 4.他要有返回结果的能力,所以需要接受观察者的监听容器(Consumer,Subscriber),这也是需要写在函数之中的。

  • 5.他要有处理多线程并能返回到主线程的能力,因为我调用了网络请求后不可能将子线程回到主线程的操作交由View处理。

  • 6.他要避免内存泄漏,因为Present很多情况下需要用到多线程,如果持有Activity的实例,那么就会造成Activity释放的不及时。

这就是我整理出来的对Present的4点要求,下面我们一一实现。

以下主要涉及三个类,MainActivity(视图类),BasePresent(Present的基类),MainActivityPresent(MainActivity对应的Present实现类)

** 公共属性 **

我觉得把一些能够一起实现的放在基类里面,然后根据各有的特色进行继承,这样优化了代码的可读性和代码量
这里的公共属性我觉得有两个,一是回到主线程的能力,二是处理内存泄漏,不多说,先帖代码

public class BasePresent {

    private WeakReference mContext ;

    protected BasePresent(Context context){
        mContext = new WeakReference(context);
    }


    protected Context getContext(){
        return mContext.get();
    }

    protected void runOnUIThread(Runnable runnable){
        //判断Context的合理
        if(runnable==null || mContext.get() == null || !(mContext.get() instanceof Activity)){
            return ;
        }
        ((Activity)mContext.get()).runOnUiThread(runnable);

    }
}

可以看到,我们通过WeakRefrence实现了对Activity的弱应用,而且通过给子类暴露的getContext方法,一是解决了内存泄漏的问题,二是对子类感受不到处理内存泄漏过程的存在。我们用构造方法来表明,我的Present必须持有Activity对象。

** View **

对于View来说,我只需要显示界面和调用Present,所以在View中必须实现对Present的初始化

public class MainActivity extends BaseActivity {

    MainActivityPresent present ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        present = new MainActivityPresent(this);
    }
}

** 业务 **

我现在有两个需求:

  • 1.MainActivity需要进行登录操作
  • 2.MainActivity需要下载图片并监听整个下载过程

这两点有什么不同?

确实有不同,第一个需求表示我传入一个值,返回给我一个结果就行了,但是第二个需求,需要我发送请求下载,然后下载的进度要实时的返回给我。

** RxJava2 实现 **

先第一个需求,首先我们不写MainActivity,我们写Present

首先我们需要有一个方法,

MainActivityPresent.java:
public void login(final Login login , final Consumer consumer){
  ...
}

我们可以看到,我们登陆,需要接受View传给我的登陆信息,这里用Login,从而进行对数据的处理,处理完成后,需要返回结果给View,所以这里需要Consumer类,我们写一个完整的。 tip:使用final因为有用到线程读取数据

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void login(final Login login , final Consumer consumer){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //登陆代码.....
                LogUtils.d("login");
                //runOnUIThread
                String result = "登陆成功";
                final Flowable flowable = Flowable.just(result);
                runOnUIThread(new Runnable() {
                    @Override
                    public void run() {
                        flowable.subscribe(consumer);
                    }
                });

            }
        }).start();
}
}

重点有两句话

 final Flowable flowable = Flowable.just(result);
 flowable.subscribe(consumer);

这里我们创建了一个Flowable对象,传入结果即将要返回的结果result ,在登陆完成后我们通过第二句代码来反馈给View。我们可以看到第二句话写在了runOnUIThread中,第二句话执行意味着回馈View

接下来我们实现MainActivity的调用

MainActivity.java:
//对于只需要结果的数据,可以使用简单的Consumer
present.login(new Login(), new Consumer() {
    @Override
     public void accept(@NonNull String s) throws Exception {
        //登陆结果,s表示view需要present返回的类型
        LogUtils.d("accept");
         showTip(s);
     }
});

可以看到,我们调用时实现了Consumer类,并重载了accept方法,这个方法便是在登陆处理完成后Present回调的方法。


下面我们实现第二个需求,第二个需求强调过程性,我们只能使用Subscriber来处理这个需求。

也是,第一步,写Present

方法

MainActivityPresent.java:
public void downloadImage(final String url ,final Subscriber subscriber){}

一样的,就不多说了,下面帖全部代码

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void downloadImage(final String url ,final Subscriber subscriber){

        Flowable flowable = Flowable.create(new FlowableOnSubscribe() {
            @Override
            public void subscribe(final FlowableEmitter e) throws Exception {
                LogUtils.d("subscribe");
                //下载代码
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3000);
                            //传回更新数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onNext(47);
                                }
                            });
                            Thread.sleep(3000);
                            //传回下载完成数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onComplete();
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }, BackpressureStrategy.BUFFER);
        flowable.subscribe(subscriber);

    }


}

我们可以看到过程很复杂,我们实现Flowable的方式也不同,这里最后也有一句,flowable.subscribe(subscriber); 这里注意的是,这句话执行并不意味着回馈消息,而是正式的注册监听,相当于关联起来。回馈消息重载的subscribe里面。

我们可以看到在subscribe 我开启了子线程,过3秒后我回到主线程执行了e.onNext(47); 又过3秒我回到主线程执行了e.onComplete(); 这里你可能不清楚含义,我先大致说一下,第一句话表示下载过程时的实时更新反馈,第二句话表示完成下载后的反馈。

好了 我们贴MainActivity的调用代码

MainActivity.java:
    //对于需要过程的数据,需要用Subscriber,我们需要一个进度,这里选用Integer为进度消息
    present.downloadImage("", new Subscriber() {
        @Override
        public void onSubscribe(Subscription s) {
            LogUtils.d("onSubscribe");
            //开始请求
            showTip("start", Toast.LENGTH_SHORT);
            s.request(Long.MAX_VALUE);
        }

        @Override
        public void onNext(Integer integer) {
            LogUtils.d("onNext");
            //进度有更新
            showTip(integer+"", Toast.LENGTH_SHORT);
        }

        @Override
        public void onError(Throwable t) {
            LogUtils.d("onError");
            //下载出错
        }

        @Override
        public void onComplete() {
            LogUtils.d("onComplete");
            //下载完成
            showTip("complete");
        }
    });

看到了什么?我们实现Subscriber类时,我们重载了onNext方法,onComplete方法,是不是和上面对应起来了? 是的,在MainActivityPresent中的 ”过3秒后我回到主线程执行了e.onNext(47); 又过3秒我回到主线程执行了e.onComplete();” 和这里对应,那里反馈的消息在这里被调用。

,很难懂,自己慢慢理解

贴个所有的代码

public class BasePresent {

    private WeakReference mContext ;

    protected BasePresent(Context context){
        mContext = new WeakReference(context);
    }


    protected Context getContext(){
        return mContext.get();
    }

    protected void runOnUIThread(Runnable runnable){
        //判断Context的合理
        if(runnable==null || mContext.get() == null || !(mContext.get() instanceof Activity)){
            return ;
        }
        ((Activity)mContext.get()).runOnUiThread(runnable);

    }
}

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void login(final Login login , final Consumer consumer){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //登陆代码.....
                LogUtils.d("login");
                //runOnUIThread
                String result = "登陆成功";
                final Flowable flowable = Flowable.just(result);
                runOnUIThread(new Runnable() {
                    @Override
                    public void run() {
                        flowable.subscribe(consumer);
                    }
                });

            }
        }).start();


    }

    public void downloadImage(final String url ,final Subscriber subscriber){

        Flowable flowable = Flowable.create(new FlowableOnSubscribe() {
            @Override
            public void subscribe(final FlowableEmitter e) throws Exception {
                LogUtils.d("subscribe");
                //下载代码
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3000);
                            //传回更新数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onNext(47);
                                }
                            });
                            Thread.sleep(3000);
                            //传回下载完成数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onComplete();
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }, BackpressureStrategy.BUFFER);
        flowable.subscribe(subscriber);

    }


}
public class MainActivity extends BaseActivity {

    MainActivityPresent present ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        present = new MainActivityPresent(this);

        //对于只需要结果的数据,可以使用简单的Consumer
        present.login(new Login(), new Consumer() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                //登陆结果,s表示view需要present返回的类型
                LogUtils.d("accept");
                //showTip(s);
            }
        });

        //对于需要过程的数据,需要用Subscriber,我们需要一个进度,这里选用Integer为进度消息
        present.downloadImage("", new Subscriber() {
            @Override
            public void onSubscribe(Subscription s) {
                    LogUtils.d("onSubscribe");
                //开始请求
                showTip("start", Toast.LENGTH_SHORT);
                s.request(Long.MAX_VALUE);
            }

            @Override
            public void onNext(Integer integer) {
                LogUtils.d("onNext");
                //进度有更新
                showTip(integer+"", Toast.LENGTH_SHORT);
            }

            @Override
            public void onError(Throwable t) {
                LogUtils.d("onError");
                //下载出错
            }

            @Override
            public void onComplete() {
                LogUtils.d("onComplete");
                //下载完成
                showTip("complete");
            }
        });
    }
}

你可能感兴趣的:(RxJava实现Android MVP)