转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/53674161
本文出自:【顾林海的博客】

##前言
Retrofit,一个时尚的代名词,好像不知道Retrofit就不算Android开发工程师了,因此我也来时尚一把,写这篇文章旨在使广大开发者能根据这篇浅薄的文章来了解Retrofit,并将它用到我们的项目中去,当然Retrofit和RxJava结合起来用是非常酸爽的。文章开头会先去介绍Retrofit,并单独使用Retrofit,后面会将Retrofit和RxJava结合起来使用,最后会封装一个Retrofit和RxJava结合的请求框架。

##Retrofit介绍

Retrofit出自Square公司,是一个类型安全的REST安卓客户端请求库。这个库为网络认证、API请求以及用OkHttp发送网络请求提供了强大的框架 ,当然OkHttp也是出自这家公司。

在漫长的时间里,Retrofit经历了从1.x到2.1(最新版请参看这里“https://github.com/square/retrofit”),相比retrofit1.x来说,retrofit2.x更新了几个不错的功能点。

##实例一(单独使用Retrofit )

该实例只会讲解单纯使用 Retrofit的用法,源码位于底下github地址,实例一位于demo1包下。

使用 Retrofit 前我们需要做以下两件事:

  • 在app/build.gradle 中引入 Retrofit。
  • 在AndroidManifest中添加网络请求权限。

在gradle中引入 Retrofit:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

在AndroidManifest中添加网络请求权限:

下面正式我们的Retrofit使用之旅。

###步骤一:创建我们的请求API(Service)

这里的请求API其实就是我们的向服务端请求的接口地址。Retrofit2.x在定义Service时,已经不区分同步和异步之分了。可以直接看下面的代码,建议大家边看文章边动手撸下代码,代码中的接口地址替换成你们公司或是自己的服务器的地址。在Retrofit中使用注解的方式来区分请求类型.比如@GET("")表示一个GET请求,括号中的内容为请求的地址.

public interface APIService {    @GET("getBrandBanner.php")    Call getBanner(@Query("uid") String _uid, @Query("token") String _token);    @GET("getHomePager.php")    Call getHomePager();    @FormUrlEncoded    @POST("editUserInfo.php")    Call postIP(@Field("name") String name, @Field("age") int age);}
以上定义了两个请求方式,分别是Get和Post请求,其中Get请求分为无参和有参请求。至此接口地址已经创建完毕。

###步骤二:创建Retrofit实例

在请求接口的API定义完毕后,就需要使用Retrofit Builder类,来指定Service的baseUrl(也就是域名)。

在Activity中编写代码:

private static final String API_URL = "http://n1.glh.la/apps/";Retrofit retrofit = new Retrofit.Builder().baseUrl(API_URL).build();APIService apiService = retrofit.create(APIService.class);Call responseBodyCall = apiService.getBanner("10915", "585234059ab68");
创建完Retrofit实例后,通过该实例创建APIService,接着通过APIService中定义的方法来获取Call对象。前置工作已经准备完毕,剩下的就是进行请求。 ###步骤三:请求(异步与同步)

一、同步请求

同步请求使用execute方法,但不能在UI线程中执行,否则会阻塞UI线程,引起NetwordOnMainThreadException异常。因此,这里使用handler+thread的方式来进行请求,在子线程中请求数据,并通过handler来刷新界面。

handler:

private static class MyHandler extends Handler {    WeakReference weakReference;    public MyHandler(DemoActivity1 activity) {        weakReference = new WeakReference<>(activity);    }    @Override    public void handleMessage(Message msg) {        DemoActivity1 activity = weakReference.get();        if (activity != null) {            String json = (String) msg.obj;            activity.setData(json);        }        super.handleMessage(msg);    }}

Thead:

private static class MyThread extends Thread {    private MyHandler myHandler;    Call bodyResponse;    public MyThread(Call responseBodyCall, MyHandler handler) {        bodyResponse = responseBodyCall;        myHandler = handler;    }    @Override    public void run() {        super.run();        try {            Response body = bodyResponse.execute();            Message message = new Message();            message.obj = body.body().string();            myHandler.sendMessage(message);        } catch (IOException e) {            e.printStackTrace();        }    }}

使用:

/** * 同步 * * @param responseBodyCall */private void synSendRequest(Call responseBodyCall) {    MyHandler myHandler = new MyHandler(this);    MyThread myThread = new MyThread(responseBodyCall, myHandler);    myThread.start();}private void setData(String json) {    tv_show.setText(json);}

同步请求的整体流程大致就这样了。

二、异步请求

相比同步请求方式,异步比较简单,因此建议使用异步请求方式,异步请求方式使用enqueue方法,并通过回调Callback 泛型接口的两个方法:

/** * 异步 * * @param responseBodyCall */private void asySendRequest(Call responseBodyCall) {    responseBodyCall.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response response) {            try {                tv_show.setText(response.body().string());            } catch (IOException e) {                e.printStackTrace();            }        }        @Override        public void onFailure(Call call, Throwable t) {            tv_show.setText("error");        }    });}

###其它一些注意事项

service 的模式变成Call的形式的原因是为了让正在进行的事务可以被取消。要做到这点,你只需调用call.cancel()。

##实例二(Retrofit 与 Gson)

当然如果你想把json字符串解析成DAO(实体类对象),在Retrofit2.x中,Converter不再包含其中,因此需要我们把Gson Converter依赖添加进来,此实例源码在源文件中的demo2包下。

添加Gson Converter:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'
demo1下的程序进行修改如下: ###修改一:接口请求
public interface APIService {    @GET("getBrandBanner.php")    Call getBanner(@Query("uid") String _uid, @Query("token") String _token);}

在定义接口请求时,我们传入了一个HttpResult类,它是我们从服务器返回的json串解析后的实体类。


###修改二:创建Retrofit实例

Retrofit retrofit = new Retrofit.Builder().baseUrl(API_URL).addConverterFactory(GsonConverterFactory.create()).build();APIService apiService = retrofit.create(APIService.class);Call responseBodyCall = apiService.getBanner("10915", "58524bb42c9ca");
我们在通过Retrofit Builder类来构造Retrofit实例时插入了一个Converter(Gson Converter)。 ###修改三:请求 ####同步请求
/** * 同步 * * @param responseBodyCall */private void synSendRequest(Call responseBodyCall) {    MyHandler myHandler = new MyHandler(this);    MyThread myThread = new MyThread(responseBodyCall, myHandler);    myThread.start();}private void setData(String data) {    tv_show.setText(data);}private static class MyHandler extends Handler {    WeakReference weakReference;    public MyHandler(DemoActivity2 activity) {        weakReference = new WeakReference<>(activity);    }    @Override    public void handleMessage(Message msg) {        DemoActivity2 activity = weakReference.get();        if (activity != null) {            HttpResult hotBean = (HttpResult) msg.obj;            if (hotBean != null) {                activity.setData(hotBean.data.pc.number);            }        }        super.handleMessage(msg);    }}private static class MyThread extends Thread {    private MyHandler myHandler;    Call bodyResponse;    public MyThread(Call responseBodyCall, MyHandler handler) {        bodyResponse = responseBodyCall;        myHandler = handler;    }    @Override    public void run() {        super.run();        try {            Response body = bodyResponse.execute();            Message message = new Message();            message.obj = body.body();            myHandler.sendMessage(message);        } catch (IOException e) {            e.printStackTrace();        }    }}

####异步请求

/** * 异步 * * @param responseBodyCall */private void asySendRequest(Call responseBodyCall) {    responseBodyCall.enqueue(new Callback() {        @Override        public void onResponse(Call call, Response response) {            HotBean hotBean = response.body().data;            tv_show.setText(hotBean.pc.number);        }        @Override        public void onFailure(Call call, Throwable t) {            tv_show.setText("error");        }    });}
##实例三(Retrofit与RxJava )

经历了上面的两个例子,大家对Retrofit的使用已经有了充分的认识了吧,如果不满足于此,可以继续看下去,因为高潮马上来了,接下来会讲解Retrofit与RxJava的结合使用。

###RxJava介绍

想来想去对RxJava介绍的文章,网上多的是,当然我认为这篇文章《给Android开发者的RxJava讲解》("http://gank.io/post/560e15be2dca930e00da1083")还是很不错,所以啊,我就不介绍了,哈哈哈。。。。。,强烈建议大家将RxJava讲解这篇文章看看,当然,不看也没问题,除非你只是拿来就用,否则作为一个有"节操"的程序员,还是老老实实的研究下。

###正题

Retrofit2.x中有个机制,叫做CallAdapter,而Retrofit团队已经提供了RxJava的CallAdapter,这时就需要在app/build.gradle中引入以下依赖:

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'compile 'io.reactivex:rxjava:1.1.0'compile 'io.reactivex:rxandroid:1.1.0'

在之前例子中,为了使用同步请求方式,需要自己创建线程,过程比较繁琐,所以只能使用异步方式,基于此,使用RxJava来解决异步的问题,代码实例在demo3包下。

###步骤一:请求接口

在创建请求接口时,我们就可以将Service作为Observable返回:

public interface APIService {    @GET("getBrandBanner.php")    Observable getBanner(@Query("uid") String _uid, @Query("token") String _token);}

###步骤二:创建Retrofit实例

//step1Retrofit retrofit = new Retrofit.Builder().baseUrl(API_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();APIService apiService = retrofit.create(APIService.class);Observable httpResultObservable = apiService.getBanner("10915", "58524bb42c9ca");
使用CallAdapter这种机制,可以在 Retrofit Builder 链中调用addCallAdapterFactory方法。

###步骤三:请求

httpResultObservable.subscribeOn(Schedulers.io())        .observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {    @Override    public void onCompleted() {        tv_show.append("请求结束");    }    @Override    public void onError(Throwable e) {        tv_show.append("请求错误");    }    @Override    public void onNext(HttpResult httpResult) {        tv_show.append(httpResult.data.pc.number);    }    @Override    public void onStart() {        tv_show.append("请求开始");    }});
上面指定subscribe发生在IO线程中,而指定的Subscriber的回调发生在Android的UI线程中。

呼~~~~,终于把上面的例子写完了,天已经黑了,看看还有什么要讲的,好吧,每次这样请求无意间代码量就增多了,而我们理想中的请求方式应该是这样的,在Activity中是这样的请求的:

private void getNews() {    MainHttpRequest.getInstance().getBanner(new ListenerSubscriber>(getNewsListener, DemoActivity4.this));}
接着通过回调获取我们想要的数据:
private OnFunctionListener getNewsListener = new OnFunctionListener>() {    @Override    public void success(ArrayList o) {        tv_show.setText(o.get(0).lname);    }    @Override    public void fail(String message) {    }};
并且服务端返回的信息,我们应该是抽取其中有用的信息,而code 、message、success、client等等信息不是我们应该关心的,就拿下面的json串来说:
{    "code":"200",    "message":"数据返回成功",    "success":true,    "data":[        {            "id":"1",            "lname":"香水合集 | 该换上适合秋天的味道啦~"        },        {            "id":"3",            "lname":"IOPE水滢多效气垫腮红"        },        {            "id":"0",            "lname":"单品小记∣毛孔收收收?痘痘消消消?"        },        {            "id":"4",            "lname":"雅诗兰黛肌透修护精萃蜜"        }    ]}
我们应该是关心data节点下的json串,因此,不管是为了省代码量还是获取数据方便,我们都有必要对这些进行一定量的封装。 ##实例四:封装

还是拿上面的json串来说事,在这json串中我们业务层应该是只关心data节点下的数据,因此定义一个HttpResult类:

public class HttpResult {    private int code;    private String message;    private boolean success;    private T data;    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }    public boolean isSuccess() {        return success;    }    public void setSuccess(boolean success) {        this.success = success;    }    public T getData() {        return data;    }    public void setData(T data) {        this.data = data;    }}
接着自定义一个Func1的类,用于变换时获取data部分的数据:
/** * 用来统一处理Http的resultCode,并将HttpResult的Data部分剥离出来返回给subscriber * * @param  Subscriber真正需要的数据类型,也就是Data部分的数据类型 */public class HttpResultFunc implements Func1, T> {    @Override    public T call(HttpResult httpResult) {        if (httpResult.isSuccess()) {            Log.e("TAG", "response error");        }        return httpResult.getData();    }}
自定义一个Converter类用于Gson解析:
public class ResponseConvertFactory extends Converter.Factory {    private final Gson gson;    public static ResponseConvertFactory create() {        return create(new Gson());    }    public static ResponseConvertFactory create(Gson gson) {        return new ResponseConvertFactory(gson);    }    private ResponseConvertFactory(Gson gson) {        if (gson == null) {            throw new NullPointerException("gson == null");        }        this.gson = gson;    }    @Override    public Converter responseBodyConverter(Type type, Annotation[] annotations,                                                            Retrofit retrofit) {        return new GsonResponseBodyConverter<>(gson, type);    }}
``` class GsonResponseBodyConverter implements Converter

}



这样定义后,我们可以在底层根据返回数据的一些参数来判别一些错误类型,方便处理。创建一个单例的Http类:

public class Http {

public static final String BASE_URL = "http://n1.glh.la/apps_T1/";private static final int DEFAULT_TIMEOUT = 5;private Retrofit retrofit;//构造方法私有private Http() {    OkHttpClient.Builder builder = new OkHttpClient.Builder();    builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);    retrofit = new Retrofit.Builder()            .client(builder.build())            .addConverterFactory(ResponseConvertFactory.create())            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())            .baseUrl(BASE_URL)            .build();}private static class SingletonHolder {    private static final Http INSTANCE = new Http();}public Retrofit getRetrofit() {    return retrofit;}public static Http getInstance() {    return SingletonHolder.INSTANCE;}public  void getData(Observable o, Subscriber s) {    o.subscribeOn(Schedulers.io())            .unsubscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(s);}

}



最后自定义一个Subscriber类,用于请求监听,比如在这里显示一个加载框或者是对一些错误码的处理:

public class ListenerSubscriber extends Subscriber {

private OnFunctionListener mSubscriberOnNextListener;private Context context;public ListenerSubscriber(OnFunctionListener mSubscriberOnNextListener, Context context) {    this.mSubscriberOnNextListener = mSubscriberOnNextListener;    this.context = context;}@Overridepublic void onStart() {}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {    if (mSubscriberOnNextListener != null) {        mSubscriberOnNextListener.fail("error");    }}/** * 将onNext方法中的返回结果交给Activity或Fragment自己处理 * * @param t 创建Subscriber时的泛型类型 */@Overridepublic void onNext(T t) {    if (mSubscriberOnNextListener != null) {        mSubscriberOnNextListener.success(t);    }}

}



public interface OnFunctionListener {
void success(T t);
void fail(String message);
}



整体封装完毕后,再在业务层将上面请求的方式再次进行封装一遍:

/**

  • 首页相关请求
  • Created by glh on 2016-12-15.
    */
    public interface HomeCarouselService {
    @GET(“getHomeCarousel.php”)
    Observable getNews();
    }

/**

  • 首页相关的网络请求

  • Created by glh on 2016-12-14.
    */
    public class MainHttpRequest {

    private HomeCarouselService mHomeCarouselService;
    private Http mHttpMethods;

    private MainHttpRequest() {
    mHttpMethods = Http.getInstance();
    mHomeCarouselService = mHttpMethods.getRetrofit().create(HomeCarouselService.class);
    }

    private static class SingletonHolder {
    private static final MainHttpRequest INSTANCE = new MainHttpRequest();
    }

    //获取单例
    public static MainHttpRequest getInstance() {
    return SingletonHolder.INSTANCE;
    }

    /**

    • 获取广告
    • @param subscriber 由调用者传过来的观察者对象
      */
      public void getBanner(Subscriber subscriber) {
      Observable observable = mHomeCarouselService.getNews()
      .map(new HttpResultFunc());
      mHttpMethods.getData(observable, subscriber);
      }

}



创建实体类:

public class NewsBean {
public String id;
public String lname;
public String tid;
public String imgurl;
public String desc;
public String ptype;
public String url;
}

完整源码在源文件的demo4中。

##项目下载地址
> 以下是完整的github项目地址,欢迎多多star和fork。> github项目源码地址:[点击【项目源码】](https://github.com/LinhaiGu/Retrofit_RxJava)

更多相关文章

  1. Android中的Activity之间传递自定义类型的List的方法
  2. Android(安卓)四种加载方式详解(standard singleTop singleTask s
  3. AIDL入门
  4. android 使用服务读取串口数据实例
  5. android按键驱动开发实例1(修改一个按键)
  6. android利用post方式与web服务器通信
  7. 【Android(安卓)开发】 : Activity之间传递数据的几种方式
  8. android中的5个布局方式
  9. Android(安卓)NFC源码浅析

随机推荐

  1. php 异常处理有什么用?
  2. 分享一个PHP写的命令行音乐搜索下载器
  3. 关于PHP进程防止内存溢出的排查
  4. php模拟qq登录代码
  5. php base64如何进行URL字符串编码和解码?
  6. PHP实现长轮询【代码示例】
  7. PHP中数组规范和自定义集合
  8. 带你一分钟了解php的四大特性八大优势(详
  9. PHP SPL 标准库之 Countable
  10. PHP之微服务协程框架Swoft