使用MVP+Retrofit+RxJava实现的的Android Demo (下)使用Retrofit+RxJava处理网络请求

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kbkaaa/article/details/70641952

上篇文章介绍了MVP的实现,这篇文章将介绍Retrofit+RxJava实现网络请求。

先重新贴一下需求

从网络Api获取Json格式的笑话数据,通过列表方式显示,列表分页显示,当上拉到最后一个数据是,自动从网络加载数据并显示,在顶端进行下拉式刷新数据。

最终效果图:
效果图
App下载地址: http://a.app.qq.com/o/simple.jsp?pkgname=chenyu.jokes
微信扫描下载APP:
App二维码
源码地址: https://github.com/zhongchenyu/jokes

Retrofit的使用

建立Api接口文件

创建ServiceAPI接口文件,代码如下:

package chenyu.jokes.network;

import chenyu.jokes.model.Response;
import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;

/**
 * Created by chenyu on 2017/3/3.
 */

public interface ServerAPI {
  String ENDPOINT = "http://119.23.13.228";

  @GET("/content.php") Observable<Response> getJokes(
      @Query("page") int page
  );

  @GET("/img.php") Observable<Response> getFunPic(
      @Query("page") int page
  );

  @GET("/blacklist.json") Observable<Response> getBlackList();
}

ENDPOINT 是服务器的基础地址,后面声明了3个Api接口,我们只看下第一个,后面的类似。

@GET("/content.php") Observable<Response> getJokes(
      @Query("page") int page
  );

注解@GET("/content.php") 表示请求是GET方式,访问的地址是ENDPOINT加括号里的字符串,即http://119.23.13.228/content.php

函数getJokes 带有一个参数page,page被注解@Query("page") 修饰,表示发送此GET请求时会带一个参数page,其值为getJokes调用时传递的值。

返回类型Observable<Response> 表示返回值是个RxJava的Observable类,泛型为之前定义的Model类Response。这样对于Http请求后返回的Json数据,会解析成Response对象,并转换成Observable对象,方便后续通过RxJava进行异步处理。

Response类:

package chenyu.jokes.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.parceler.Parcel;

/**
 * Created by chenyu on 2017/3/3.
 */

@Parcel @JsonIgnoreProperties(ignoreUnknown = true) public class Response {
  public Result result;
  @JsonProperty("error_code") public int errorCode;
  public String reason;
}

实现API接口

声明了接口之后,还需要对接口进行实现,我们在APP类的onCreate里进行,代码如下:

package chenyu.jokes.app;

import android.support.multidex.MultiDexApplication;
import android.text.Html;
import android.text.Spanned;
import chenyu.jokes.network.ServerAPI;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;

/**
 * Created by chenyu on 2017/3/3.
 */

public class App extends MultiDexApplication {

  private static ServerAPI serverAPI;

  @Override public void onCreate(){
    super.onCreate();

    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(logging).build();

    serverAPI = new Retrofit.Builder()
        .baseUrl(ServerAPI.ENDPOINT)
        .addConverterFactory(JacksonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(httpClient)
        .build()
        .create(ServerAPI.class);
  }
  public static ServerAPI getServerAPI() {
    return serverAPI;
  }

为了调试方便,加了日志拦截器,首先创建一个HttpLoggingInterceptor,将日志级别设为最高级别BODY,会将HTTP请求和相应几乎所有内容都记录下来。再创建一个OKHttpClient,添加刚建立的日志拦截器。

接下来就是要实例化serverAPI了,这里通过new一个Retrofit.Builder()来建立。

.baseUrl(ServerAPI.ENDPOINT) 添加API基础地址;
.addConverterFactory(JacksonConverterFactory.create())添加 对返回的Json数据进行解析的Factory,需要配合我们在Model类种添加的Jackson注解。
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 添加RxJava适配工厂,将解析的数据转换成RxJava中的类。
.client(httpClient) 添加前面建立的包含日志拦截的httpClient。
.build().create(ServerAPI.class); 创建并实现ServiceAPI.class中声明的函数。

这样ServiceAPI就已经实例化了,最后公开一个getServerAPI(),以便在需要的地方获取ServiceAPI实例。

接口调用和RxJava处理

我们用的MVP架构,网络请求是在Presenter中处理的,这里我们看一下JokePresenter类是如何获取并处理joke接口的数据的。

上篇文件已经讲过,在Presenter的onCreate()函数中注册网络请求,再调用start(int requestId)即可完成网络请求,代码如下:

    restartableFirst(GET_JOKES,
        new Func0<Observable<ArrayList<Data>>>() {
          @Override public Observable<ArrayList<Data>> call() {
            return App.getServerAPI().getJokes(mPage).subscribeOn(io()).observeOn(mainThread())
                .flatMap(errorCodeProcess);
          }
        },
        new Action2<JokeFragment, ArrayList<Data>>() {
          @Override public void call(JokeFragment jokeFragment, ArrayList<Data> data) {
            jokeFragment.onItemsNext(data);
          }
        },
        new Action2<JokeFragment, Throwable>() {
          @Override public void call(JokeFragment jokeFragment, Throwable throwable) {
            jokeFragment.onItemsError(throwable);
          }
        }
    );

restartableFirst有4个参数,第一个为请求的ID,在第二个参数中重写了Func0的call()函数,Func0是RxJava的接口,代表要实现的函数没有输入参数,但是有返回值,我们具体看一下:
App.getServerAPI().getJokes(mPage) 调用上一节中讲到的API接口,请求地mPage页的数据。

.subscribeOn(io()).observeOn(mainThread()) 这里是RxJava的线程切换,同时也用到了RxAndroid中的io()和mainThread(),分别代表IO线程和主线程。

我们知道,网络请求是耗时任务,不能放在主线程里,但是非主线程是不能更新UI的,更新UI只能在主线程里进行。如果不用RxJava,则需要使用Thread结合Handle来处理,需要各种嵌套和回调等,代码易读性就下降了。

而RxJava的优势这时候就体现出来了,调用两个简短的函数就完成了网络请求和UI更新的线程切换,并且可以保持代码的链式结构不中断,代码简洁明了。

至于subscribeOn和observeOn的含义,设计到观察者模式,RxJava就是基于观察者模式的,API返回的是Observable,可以理解成被观察对象,subscribeOn代表订阅观察对象时使用的线程,也就是网络请求产生观察对象的过程,在我们这段代码中就是控制网络请求使用的线程。而observeOn代表对Observable观察处理用的线程,在这里就是处理API返回结果,并通知View层进行更新时使用的线程。

.flatMap(errorCodeProcess) 是用来对返回数据进行预处理的,API返回的数据保护error_code,如果error_code不为0,则代表数据出错,这时就可以直接抛出异常,进入异常处理流程,跳过UI更新;而如果error_code不为0,代表数据正常,这时我们也对数据进行转换,提取出Response中的Data信息,交给后续处理。

flatMap是RxJava的操作符,用来对Observable进行处理,返回的对象还是Observable类型,看下errorCodeProcess的代码:

private Func1 errorCodeProcess = new Func1<Response, Observable<ArrayList<Data>>>() {
    @Override public Observable<ArrayList<Data>> call(Response response) {
      if(response.errorCode !=0) {
        return Observable.error(new Throwable(response.reason));
      }
      return Observable.just(response.result.data);
    }
  };

这里重写了Func1的call函数,Func1是Rxjava中的接口,代表要实现的函数有一个输入参数,一个返回值。这里的输入时getJokes函数的返回值,判断下response的errorCode,如果非0,则用response的reason生成一个Throwable并通过Observale.error()抛出;如果errorCode为0,则提取出response中的data,生成一个新的Observable作为返回值。

restartableFirst的第三个参数重写了RxJava的Action2接口,代表有两个输入参数,没有返回值,这里两个参数分别是JokeFragment和ArrayList,其实就是View层和Model层。Action2会在数据请求处理成功后执行,通知View层更加返回的Model数据更新UI。

restartableFirst的第四个参数是可选参数,也是重写了Action2,会在网络请求出错后执行,用来处理异常,形式和第三个参数基本一致,只是把Model换成了Throwable,请求过程中出现的异常,包括Http异常,还有我们自定义的在errorCode不为0时抛出的异常,都会在这里处理。

这一部分是Nucleus MVP框架和RxJava结合实现的,如果再结合Lambda表达式,代码会变得异常简洁、清晰,看效果:
这里写图片描述

可以看出,MVP的代码分割,Retrofit+RxJava的接口链式调用,再加上Lambda表达式的缩减,简单几行代码,就能讲清楚网络请求、数据处理、线程切换、UI更新、异常处理的整套流程,在后续项目维护和再开发中提供很大的便利,如果加以封装,也能大大减少代码工作量。

猜你喜欢

转载自blog.csdn.net/kbkaaa/article/details/70641952