使用RxAndroid配合MVP模式实现异步网络请求,更新ui

各位好,写这篇文章主要是我在工作时发现了一个问题,现在使用RxAndroid解决了。


问题是:

我工作的项目是使用mvp模式写的,(关于什么是mvp,可参考:http://blog.csdn.net/lmj623565791/article/details/46596109)

而大家应该都知道,如果我们没有开启线程,则你代码里写的所有的任务将都在主线程中执行。

而主线程是不能执行耗时操作的(如:网络操作、访问数据库等)。

如果我们需要请求网络获取了数据之后更新ui界面,我们就必须开启一个线程来访问网络,获取了数据之后更新界面元素。

Activity中有个runOnUiThread的方法,可以使其在ui线程中运行。

而问题在于我的项目是使用mvp模式,m:处理逻辑,然后将处理的逻辑交给p层,p:是m层与v层的纽带。

而我执行网络操作是放在m层处理的,如果要用runOnUiThread这个方法就得把activity传进来,或者最后传到activity去,这都会乱了结构,使代码凌乱不堪。

在找解决办法时,我遇见了RxAndroid。(关于RxAndroid的基本使用,可参考:http://www.jianshu.com/p/51a8d2ff8697)


RxAndroid是RxJava的一个变体,它们都属于函数响应式编程

RxAndroid有什么作用呢?

1、函数响应式编程
2、异步
3、事件驱动(事件作为可观察序列)
4、基于观察者模式
5、组合式
6、专门出错处理
7、适用于处理并发问题

这不是我所注重,我最注重的是:提供了可设置计算的所在线程以及更新 UI 时可在主线程更新。

这里关于mvp模式与RxAndroid使用啥的就不说了,我主要将它们两者结合。


下面demo环节:

一个很简单的demo,就是模拟登录操作。

结构如下:


biz:数据处理层

ApiData:模拟后台数据

LoginBiz:mvp中的m层,用于处理登录逻辑

User:用户实体对象

view:界面层

ILoginView:登录界面,是一个接口,如:展示进度条、隐藏进度条、展示数据等

MainActivity:ILoginView的实现类

persenter:连接view与biz的纽带

LoginPersenter:请求LoginBiz获取数据,使用ILoginView层更新界面。


代码环节:

MainActivity代码:

public class MainActivity extends Activity implements ILoginView {

    private EditText editText;
    private TextView textView;
    private LoginPresenter loginPresenter;
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.editText);
        textView = (TextView) findViewById(R.id.textView);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);

        loginPresenter = new LoginPresenter(this);
    }



    public void onClick(View view){
        String userName = editText.getText().toString();
        loginPresenter.doLogin(userName);
    }

    @Override
    public void showView(String userName) {
        textView.setText(userName);
    }

    @Override
    public void showLoadding() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoadding() {
        progressBar.setVisibility(View.GONE);
    }
}


ILoginView代码:

public interface ILoginView {

    void showView(String userName);
    void showLoadding();
    void hideLoadding();
}

layout代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用户名"/>

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DO"
        android:onClick="onClick"/>

    <ProgressBar
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/progressBar"
        android:layout_gravity="center_horizontal"
        android:visibility="gone"/>

</LinearLayout>

实体类User代码:

public class User {

    public String name;
    public String pwd;
}


LoginBiz代码:

public class LoginBiz {

    private String TAG = "loginBiz";

    public void doLogin(final OnGetDataListener<User> listener, final User user){
        rx.Observable.create(new Observable.OnSubscribe<User>() {
            @Override
            public void call(Subscriber<? super User> subscriber) {
                // 模拟执行网络操作
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                User user2 = new ApiData().doLogin(user);
                subscriber.onNext(user2);
                Log.e(TAG, "------->call线程:" + Thread.currentThread().getName());
            }
        }).subscribeOn(Schedulers.newThread())      // 子线程执行网络操作
          .observeOn(AndroidSchedulers.mainThread()) // 转回主线程
          .subscribe(new Subscriber<User>() {
              @Override
              public void onCompleted() {
              }

              @Override
              public void onError(Throwable throwable) {
              }

              @Override
              public void onNext(User user) {
                  if (user != null) {
                      listener.success(user);
                  }else{
                      listener.fail(user,"用户名错误");
                  }
              }
          });
    }
}

可见使用  Schedulers.newThread() 是新见了一个线程执行的网络操作,使用observeOn(AndroidSchedulers.manThread())又切换到了主线程。

解决了线程来回切换问题,同时代码逻辑也十分清晰。


OnGetDataListener代码:

public interface OnGetDataListener<T> {
    void success(T response); // 网络操作成功
    void fail(T response, String msg); // 网络操作失败
}


LoginPresenter代码:

public class LoginPresenter {

    private ILoginView loginView;
    private LoginBiz loginBiz;

    public LoginPresenter(ILoginView loginView) {
        this.loginView = loginView;
        this.loginBiz = new LoginBiz();
    }

    public void doLogin(String userName){
        loginView.showLoadding(); // 展示加载条
        User user = new User();
        user.name = userName;
        loginBiz.doLogin(new OnGetDataListener<User>() {
            @Override
            public void success(User response) {
                loginView.hideLoadding(); // 隐藏加载条
                loginView.showView(response.name); // 展示数据
            }

            @Override
            public void fail(User response, String msg) {
                loginView.hideLoadding();
                loginView.showView(msg);
            }
        },user);
    }
}


最后看下Log日志:


确实是开启的新线程,放心了。


看官可以自己写个demo试试,下面是本文的源码,可下载下来运行试试

点击下载源码

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值