【第22期】观点:IT 行业加班,到底有没有价值?

RxJava简单使用、模仿访问服务器获取数据更新界面-基于mvp架构

原创 2016年08月29日 15:30:49

先看下项目结构目录-基于mvp架构


RxJava是一个实现Java响应式编程的库,让异步事件以序列的形式组织。MVP则通常用来将View业务层与Model层分离开来,两者结合起来可轻松实现业务解耦、线程控制、单元测试等等强大功能


目标:

假设有一个从服务端获取字符串并显示的手机上的简单功能。


这是一个比较典型的MVP结构图(图片来自参考文献),相比于mvc,多了两个层,一个是Presenter和DataManager层。


Activity里面包含了几个文件,一个是View层的对外接口MainView,一个是P层的Presenter。

package test.ban.com.mvp;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

import test.ban.com.mvp.presenter.MainPresenter;
import test.ban.com.mvp.view.MainView;

public class MainActivity extends Activity implements MainView {

    /**
     * View层通过注册Listener
     * 将自己的接口MainView(test.ban.com.mvp.view.MainView)交给了Presenter(P层)
     *
     * ===============白话解说:==========
     * 就是MainActivity实现了View的接口MainView,
     * 然后重写了MainView的方法onShowString()
     * 让mTextView的显示内容实现了相应的改变
     * ================================
     */

    /**
     * 抛出问题????:
     * MainActivity、MainView、MainPresenter三个文件可以看到,
     * View层通过注册Listener将自己的接口MainView交给了Presenter,
     * 而Presenter层持有Model层的也只是一个接口。
     * 通过Presenter层将业务层与展现层隔离了开来,这样的好处是什么?
     * ======================================
     * <p>
     * -------------====答案====--------------
     * 我们知道接口的一个作用通常是用来抽象行为,对外部屏蔽实现细节。
     * 所以对于View层来说,业务细节被屏蔽了,对业务层来说,展示细节被屏蔽了。
     * 而对于处于中间的Presenter层来说,它就像一个接口拼装器,把View层发出的请求传递给业务层,
     * 把业务层返回的数据又送还给View层展示,至于前后两端怎么实现的,它才不用关心。
     * --------------------------------------
     */

    TextView mTextView;
    MainPresenter mMainPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.tv);
        loadDatas();
    }

    private void loadDatas() {
        mMainPresenter = new MainPresenter().addTaskListener(this);

        /**
         * 两种获得数据的方式
         *
         * RxJava的使用场景远不止这些,线程变换、数据变换、接口顺序依赖、接口并发请求这些要求对它来说都是小菜一碟。
         * 当然,有些同学可能觉得RxJava入手有些困难,代码也会变得不那么直观,但相信只要大家慢慢熟悉它之后,它就会变得无比讨人喜欢。
         *
         * 下面列出了一些常见的RxJava的常用场景,其实还有更多的其它功能等待着大家去挖掘。
         * * 1、取数据先检查缓存的场景
         * * 2、需要等到多个接口并发取完数据,再更新
         * * 3、一个接口的请求依赖另一个API请求返回的数据
         * * 4、界面按钮需要防止连续点击的情况
         * * 5、响应式的界面
         * * 6、复杂的数据变换
         */
        //1、传统写法获得数据
        //mMainPresenter.getData();

        //2、通过Rxjava获得数据(推荐使用)
        //mMainPresenter.getDataUseRxJava();

        //2-1、Rxjava强化写法 获得数据
        mMainPresenter.getDataUseRxJavaWithCache();

    }

    //因为这个功能比较简单,只需要在设备上显示一个字符串,所以只有一个接口方法onShowString()
    @Override
    public void onShowString(String json) {
        mTextView.setText(json);
    }
}

View层的对外接口文件

package test.ban.com.mvp.view;

/**
 * Created by apple on 16/8/29.
 */

public interface MainView {
    //因为这个功能比较简单,只需要在设备上显示一个字符串,所以只有一个接口方法onShowString()
    void onShowString(String json);
}

MainPresenter层 (p层)

package test.ban.com.mvp.presenter;/**
 * Created by apple on 16/8/29.
 */

import android.os.Handler;
import android.os.Looper;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import test.ban.com.mvp.data.DataSource;
import test.ban.com.mvp.data.impl.DataSourceImpl;
import test.ban.com.mvp.data.impl.DataSourceTestImpl;
import test.ban.com.mvp.view.MainView;

/**
 * 作者:ban on 16/8/29 14:17
 */
public class MainPresenter {

    MainView mMainView;
    DataSource mDataSource;

    public MainPresenter() {
        this.mDataSource = new DataSourceImpl();
    }

    public MainPresenter test() {
        this.mDataSource = new DataSourceTestImpl();
        return this;
    }

    public MainPresenter addTaskListener(MainView viewListener) {
        this.mMainView = viewListener;
        return this;
    }

    /**
     * 很多同学可能已经发现了,Presenter层在调用业务层的时候是直接调用的,
     * 而Android规定,主线程是无法直接进行网络请求,会抛出NetworkOnMainThreadException异常。
     * <p>
     * 所以在presenter层,我们需要进行一项线程切换的工作,这样才能保证“所有的IO操作都应当在线程中完成,
     * 主线程只负责页面渲染的工作”这一优化准则。当然,Android本身提供一些方案,比如下面这种:
     */

    /**
     * 写法一:
     * 通过新建子线程进行IO读写获取数据,然后通过主线程的Looper将结果通过传回主线程进行展示,这种方案是勉强也行得通的。
     * <p>
     * 但问题有以下两点:
     * 一是线程需要额外管理,不可能每次发请求都要开启一个线程;
     * 二是适应性差,假如数据请求有先后依赖,有并行的情况,这样的写法变得脏乱无比。
     */

    public void getData() {
        final Handler mainHandler = new Handler(Looper.getMainLooper());
        new Thread(new Runnable() {
            @Override
            public void run() {
                final String str = mDataSource.getStringFromRemote();
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mMainView.onShowString(str);
                    }
                });
            }
        }).start();
    }

    /**
     * 写法二: 使用RxJava来进行线程控制
     * RxJava是一个天生用来做异步的工具,相比AsyncTask,Handler等,它的优点就是简洁,无比的简洁。
     * 在Android中使用RxJava需要加入下面两个依赖。
     * compile 'io.reactivex:rxjava:1.0.14'
     * compile 'io.reactivex:rxandroid:1.0.1'
     */

    public void getDataUseRxJava() {

        final Func1<String, String> dataAction = new Func1<String, String>() {
            @Override
            public String call(String s) {
                return s + mDataSource.getStringFromCache() + mDataSource.getStringFromRemote();
            }
        };

        Action1<String> viewAction = new Action1<String>() {
            @Override
            public void call(String s) {
                mMainView.onShowString(s);
            }
        };

        /**
         * Observable.just就是用来创建只发出一个事件就结束的Observable对象,就是发送了一个消息"Rxjava"
         *
         * ========:简单说明:========
         * dataAction是我们的数据业务逻辑,viewAction是界面的显示逻辑,
         * 通过RxJava的传递和变换,
         * dataAction会在由RxJava管理的IO线程–Schedulers.io() 中执行,
         * 而viewAction则会在UI线程–AndroidSchedulers.mainThread()中执行。
         */
        Observable.just("Rxjava")
                .observeOn(Schedulers.io())
                .map(dataAction)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(viewAction);
    }


    /**
     * RxJava当然不止这么简单,还有别的玩法,
     * 比方说进入一个界面的时候,需要先加载缓存的数据,然后再从网络获取更新的数据进行刷新。
     * 有的时候,可能还需要处理IO过程中的异常情况,加入RxJava的异常处理参数。
     */
    public void getDataUseRxJavaWithCache() {
        Func1<Boolean, String> dataAction = new Func1<Boolean, String>() {
            @Override
            public String call(Boolean isCache) {
                if (isCache) {
                    return mDataSource.getStringFromCache();
                } else {
                    return mDataSource.getStringFromRemote();
                }
            }
        };

        Action1<String> viewAction = new Action1<String>() {
            @Override
            public void call(String s) {
                mMainView.onShowString(s);
            }
        };

        Observable.just(false)
                .observeOn(Schedulers.io())
                .map(dataAction)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(viewAction, getDefaultErrorAction());

    }

    private Action1<Throwable> getDefaultErrorAction() {
        return new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        };
    }


data层

DataSource

package test.ban.com.mvp.data;

/**
 * Created by apple on 16/8/29.
 */

public interface DataSource {

    /**
     * 接口的第二个作用是可以用来切换实现。
     *
     * 从DataSource、DataSourceImpl和DataSourceTestImpl)
     * 三个文件可以看到,业务层对外的只有一个接口,实现却有两个(DataSourceImpl和DataSourceTestImpl)。
     * 从名字大家就能看出来有什么作用了,一个是正常环境的业务层实现,一个是测试环境的业务层实现。
     */

    String getStringFromRemote();
    String getStringFromCache();
}
DataSourceImpl

package test.ban.com.mvp.data.impl;/**
 * Created by apple on 16/8/29.
 */

import test.ban.com.mvp.data.DataSource;

/**
 * 作者:ban on 16/8/29 14:13
 */
public class DataSourceImpl implements DataSource {
    @Override
    public String getStringFromRemote() {
        String str = "remote hello";
        return str;
    }

    @Override
    public String getStringFromCache() {
        return "World";
    }
}

DataSourceTestImpl(测试类,在需要的时候模仿生产环境返回进行测试)

package test.ban.com.mvp.data.impl;/**
 * Created by apple on 16/8/29.
 */

import test.ban.com.mvp.data.DataSource;

/**
 * 作者:ban on 16/8/29 14:13
 */
public class DataSourceTestImpl implements DataSource {
    @Override
    public String getStringFromRemote() {
        String str = "hello Test";
        return str;
    }

    @Override
    public String getStringFromCache() {
        return "World Test";
    }
}

源码地址:http://download.csdn.net/detail/u010566681/9615918


版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

深入浅出RxJava(二:操作符)

RxJava operator介绍,介绍了RxJava中几种常见的operator的用法
  • lzyzsd
  • lzyzsd
  • 2015-03-06 08:04
  • 82389

RxAndroid2.0使用概述

传统的观察者实现java.util.Observer接口,被观察者继承java.util.Observable类,当被观察者数据项发生改变时,调用Observable的notifyObservers方...

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

数据访问更新服务在生产环境部署注意事项

除部署文档要求外,还需要修改/PGIS_S_Map/test/ms7/cases/Select.txt文件,将文件中GIS0001更换为生产环境使用的空间用户代码。

给初学者的RxJava2.0教程(二)

转自:http://www.jianshu.com/p/8818b98c44e2 前言 上一节教程讲解了最基本的RxJava2的使用, 在本节中, 我们将学习RxJava强大的线程...

给初学者的RxJava2.0教程(二)

 前言 上一节教程讲解了最基本的RxJava2的使用, 在本节中, 我们将学习RxJava强大的线程控制. 正题 还是以之前的例子, 两根水管: RxJava 正常情况下, ...

RxJava简介及在androidstudio中引入RxAndroid

RX的简介 RX = Observables + LINQ +Schedulers LINQ 语言集成查询 Language Integrated Query Schedulers 定...

Retrofit2 结合 Rxjava 解决返回的 JSON

Retrofit2 结合 Rxjava 解决返回的 JSON

RxJava----使用

基本使用 //一个最简单的实现 //一个Observable(被观察者) Observable observable = Observable.creat...

IOS异步获取数据并刷新界面dispatch_async的使用方法

在ios的开发和学习中多线程编程是必须会遇到并用到的。 在java中以及Android开发中,大量的后台运行,异步消息队列,基本都是运用了多线程来实现。  同样在,在ios移动开发和Android...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)