Android---网络编程之Retrofit2整体结构了解以及+Okhttp3+rxjava2使用

Retrofit

相关

Android—网络编程之Http协议

Android—网络编程之OkHttp3整体结构了解以及使用

Android—网络编程之Okhttp3源码解析

Android—网络编程之Retrofit2整体结构了解以及+Okhttp3+rxjava2使用

Android—网络编程之Retrofit2源码分析

Android—网络编程之Socket编程(实例)

前言

要不要写这篇文章,其实我纠结了好久,因为网上已经有好多的关于Retrofit的文章了,不乏有很经典的文章和博客,读后真的收益良多,相比以前的只会用,成长良多!但是,看完以后始终觉着那些东西是非而非,时有感觉那都不是自己的东西,毕竟那不是按照自己的思路来的,所以有必要按照自己的思路再来捋一遍,人啊,关键得有自己的想法啊,不管是在编程上还是人生路上!

贴一个我感觉写的不错的关于Retrofit的博客,就不转载了

  • Android:手把手带你深入剖析 Retrofit 2.0 源码

我也把我的心得及思路记录一下,希望朋友们也多思考,毕竟思考也是成功他老母啊!

简介

Retrofit2是基于okhttp的类型安全HTTP客户端,retrofit2只需要专注对请求的封装处理,而真正的网络请求是由okhttp发起的,然后处理返回的响应。

  • 基于Okhttp
  • 支持Restful API风格:一套互联网应用程序的API设计理论,方便不同的前端设备与后端进行通信。不错的介绍
  • 支持rxjava,进行线程间转换
  • 支持转换器序列化数据,也可以自定以转化器

    1. Gson: com.squareup.retrofit2:converter-gson
    2. Jackson: com.squareup.retrofit2:converter-jackson
    3. Moshi: com.squareup.retrofit2:converter-moshi
    4. Protobuf: com.squareup.retrofit2:converter-protobuf
    5. Wire: com.squareup.retrofit2:converter-wire
    6. Simple XML: com.squareup.retrofit2:converter-simplexml
    7. Scalars (primitives, boxed, and String):com.squareup.retrofit2:converter-scalars

基于Retrofit2是对请求接口的封装,,而我们只去关注怎样去构造一个可用的URL就行了,至于他底层怎样去处理(注解+动态代理)我们就不用去管了。

构成

按照我们分析Okhttp3的套路来一遍(这只是我自己的思路,大家尽量按自己的思路来理解),先整体把握一下Retrofit2的内容,了解其整体构成,然后到局部使用,再到底层原理

整体大概—–具体细节——-底层原理

Retrofit2整个项目分成两个包

  • retrofit2:Retrofit将REST API转换为Java接口。
  • retrofit2.http:用于控制HTTP请求行为的接口方法注解。
接口 功能
Call 向web服务器发送请求并返回响应。
CallAdapter 响应适配特定对象的链接调用
Callback 请求回调
Converter 将HTTP转换为对象。使用工厂设计模式
功能
BuiltInConverters Retrofit2内置的简单数据转换器(5种)
DefaultCallAdapterFactory 为I/O和应用程序级别的相同线程创建调用适配器。
ExecutorCallAdapterFactory 新的线程创建调用适配器
HttpException 异常,非2xx HTTP响应。
OkHttpCall 对Okhhtp3的包装
ParameterHandler 参数处理程序,将我们解析的注解参数设置到RequestBuilder里
Platform 返回当前平台
RequestBuilder 配置请求参数
Response HTTP响应
Retrofit 通过在声明的方法上使用注解,可以将Java接口转换为HTTP调用。
ServiceMethod 将接口方法的调用转换为HTTP调用。其实Retrofit的creat方法就是返回的其的方法调用。
Utils 工具类
注解 功能(这里,我分为4种注解:方法注解;标记注解;参数注解;其他)
方法注解 表示我们是以什么方法提交HTTP请求
DELETE 请求删除URL指向的资源。
GET get请求
HEAD 请求Request-URI所标识的资源响应消息报头,HEAD方法可以在响应时不返回消息体。
HTTP 使用自定义HTTP请求方法
OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项。
PATCH PATCH方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新
POST post请求
PUT 与GET相反,请求服务器存储一个资源,并用Request-URI做为其标识
标记注解 标识此次请求的特性
FormUrlEncoded 表示请求体将使用表单URL编码
Multipart 表示支持文件上传,需要上传文件时需要在方法前添加次注解
Streaming 表示处理返回的响应流,通常用于大文件下载
参数注解 为构建正常请求配置的参数
Body 适用于POST/PUT请求,参数有多个,可以封装成Body对象
Field Post方式传递简单的键值对,需要添加@FormUrlEncoded表示表单提交
FieldMap 为表单编码的请求指定键/值对。将Field封装成map集合
Part 文件上传
PartMap 以map的形式上传文件
Query 查询参数附加到URL
QueryMap Query参数比较多,那么可以通过@QueryMap方式将所有的参数集成在一个Map统一传递
QueryName 适用于参数没有值的情况
其他
Header 替换请求头
HeaderMap 需要替换的请求头比较多,可以添加到Map集合里进行统一提交
Headers 将值添加到请求头中
Path URL占位符,用于替换和动态更新URL中的字符
Url 对baseUrl不统一的情况需要此注解,用全路径覆盖baseUrl。

使用

到现在,我们对Retrofit2整体架构已经有了大概的了解,至于使用那就更加简单了。

使用流程

  • 新建一个java接口。例:
//建议 以你http返回的类型命名类型,若是Restful API风格那就更好了,可以把一系列方法都定义在这一个接口里
public interface NewService {
//baseURL(Retrofit里配置http://image.baidu.com/data/)+方法注解(GET)里的字符(imgs)+方法里面(Query注解的参数)构成一个完整资源路径
    /**
     * 获取美女图片
     * API获取途径http://www.jb51.net/article/61266.htm
     * eg: http://image.baidu.com/data/imgs?sort=0&pn=0&rn=20&col=美女&tag=全部&tag3=&p=channel&from=1
     * 通过分析,推断并验证了其中字段的含义,col表示频道,tag表示的是全部的美女,也可以是其他Tag,pn表示从第几张图片开始,rn表示获取多少张
     * @param
     * @return
     */
    //这个是适配Rxjava2以后的方法
    @Headers(CACHE_CONTROL_NETWORK)
    @GET("imgs")
    Observable getWelfarePhoto(@Query("sort") int sort,
                                              @Query("pn")int startImage,
                                              @Query("rn")int size,
                                              @Query("col")String col,
                                              @Query("tag")String tag,
                                              @Query("tag3")String tag3,
                                              @Query("p")String channel,
                                              @Query("from")int from);
    //这个是原始的                                          
    @Headers(CACHE_CONTROL_NETWORK)
    @GET("imgs")
    Call getWelfarePhotoCall(@Query("sort") int sort,
                                            @Query("pn")int startImage,
                                            @Query("rn")int size,
                                            @Query("col")String col,
                                            @Query("tag")String tag,
                                            @Query("tag3")String tag3,
                                            @Query("p")String channel,
                                            @Query("from")int from);
}
  • 配置Retrofit2属性,通过动态代理返回一个我们之前创建的接口对象
 public static  T getInstanceStringUrl(String url,Class clazz){
        Retrofit  retrofit = new Retrofit.Builder()
//                .client()//配置OKhttp客户端
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())//json转对象
//                .validateEagerly()  在Call时,是否立即验证接口中的方法配置
//                .callbackExecutor() //回调
                .build();
        T service = retrofit.create(clazz);
        return service;
    }
  • 通过接口对象调用我们接口中的方法,返回一个Call对象(适配Rxjava后,返回的是Observable对象等),然后继续异步还是同步请求网络
RetrofitClient.getInstanceStringUrl("http://image.baidu.com/data/", NewService.class)
                        .getWelfarePhotoCall(0,0,50,"美女","全部", "", "channel", 1)
                        .enqueue(new retrofit2.Callback() {
                            @Override
                            public void onResponse(retrofit2.Call call, final retrofit2.Response response) {  //因为底层是基于okhttp进行网络请求,所以需要我们自己进行线程间转换,若适配Rxjava后就没这么麻烦了。
                                //请求成功回调方法
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        tvShow.setText(response.body().col+":"+response.body().col);
                                    }
                                });
                            }
                            @Override
                            public void onFailure(retrofit2.Call call, final Throwable t) {
                                //请求失败回调方法
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        tvShow.setText(t.getMessage());
                                    }
                                });
                            }
                        });

配置okhttp:一般我们网络请求配置一个全局OKHTTP就行了,我一般是在Application里初始化。

 public static void initNet(Context context ,Cache cache, Interceptor interceptor, Interceptor netInterceptor){
        if(cache==null){
            //缓存目录
            cache = new Cache(new File(context.getCacheDir(),"cache"),1024*1024*1024);
        }
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .cache(cache)
                .connectTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true);
        if(interceptor!=null){
            builder.addInterceptor(interceptor);
        }
        if(netInterceptor!=null){
            builder.addNetworkInterceptor(netInterceptor);
        }
        okHttpClient = builder.build();
    }

下面是rxjava版的请求

NetUtils.getService(MainActivity.this)
                        .subscribe(new Observer() {
                            @Override
                            public void onSubscribe(@NonNull Disposable d) {

                            }

                            @Override
                            public void onNext(@NonNull BeautyPicture beautyPicture) {
                                tvShow.setText(beautyPicture.col+":"+beautyPicture.getTag());
                            }

                            @Override
                            public void onError(@NonNull Throwable e) {

                            }

                            @Override
                            public void onComplete() {

                            }
                        });

NetUtils类,我在这里做了一层封装,若有多个HTTP API ,直接在这里调用就行,就不用新建Retrofit配置了,因为大部分APP里的网络配置都是一样的

public class NetUtils {


    private static ObservableTransformer transformer = getSchedulers();

    public static Observable getService(RxActivity activity){
        NewService newService = RetrofitClient.getOkhttpClientServiceStringUrl("http://image.baidu.com/data/", NewService.class);
        return newService.getWelfarePhoto(0,0,50,"美女","全部", "", "channel", 1)
                .compose(transformer)
                .compose(activity.bindToLifecycle());
    }
    private static ObservableTransformer getSchedulers(){
        return new ObservableTransformer() {
            @Override
            public ObservableSource apply(@NonNull Observable upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

}
 public static  T getOkhttpClientServiceStringUrl(String url,Class tClass){
        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(url)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        T service = retrofit.create(tClass);
        return service;
    }

这样我们的网络请求到数据显示都完成了,当然上面只展示GET注解,下面我们来看一下其他的一些常用注解的使用方式。

其他注解使用方式

  • POST方式
//    http://app.pearvideo.com/clt/jsp/v2/home.jsp
//    http://app.pearvideo.com/clt/jsp/v2/getCategoryConts.jsp
//    http://app.pearvideo.com/clt/jsp/v2/content.jsp?contId=1064146
//这里我实际抓取了一下Get也可以
    @FormUrlEncoded
    @POST("getCategoryConts.jsp")
    Observable getKankanVideoFromCate(@HeaderMap HashMap headers,
                                                    @Field("hotPageidx")int page,
                                                    @Field("start")int start,
                                                    @Field("categoryId")String categoryId);

下面是我截取我的一个开源项目里的一个使用(Kotlin写的)

init {
        headersMap.put("X-Channel-Code","official")
        headersMap.put("X-Client-Agent","Xiaomi")
        headersMap.put("X-Client-Hash","2f3d6ffkda95dlz2fhju8d3s6dfges3t")
        headersMap.put("X-Client-ID","123456789123456")
        headersMap.put("X-Client-Version","2.3.2")
        headersMap.put("X-Long-Token","")
        headersMap.put("X-Platform-Type","0")
        headersMap.put("X-Platform-Version","5.0")
        headersMap.put("X-User-ID","")
    }
fun getCategoryDate(categoryId: String) {
        mCategoryId = categoryId
        var time = System.currentTimeMillis()/1000
        headersMap.put("X-Serial-Num",time.toString())
        start = 0
        RetrofitService.getKankanVideoFromCate(headersMap,page,start,categoryId)
                .doOnSubscribe { mView.showLoading() }
                .compose(mView.bindToLife())
                .subscribe(object :Observer{
                    override fun onComplete() {
                        mView.hideLoading()
                    }

                    override fun onSubscribe(d: Disposable) {
                    }

                    override fun onNext(t: VideoListDate) {
                        mView.loadVideoForCategoryidDate(t)
                        page++
                        start+=t.contList?.size!!
                    }

                    override fun onError(e: Throwable) {
                        mView.showNetError(object :EmptyErrLayout.OnReTryListener{
                            override fun onReTry() {
                                getCategoryDate(categoryId)
                            }
                        })
                    }
                })
    }

其他几种情况我就没遇到过了,请允许我在此贴一些网上的事例代码,但是通用的模式都是,我们根据实际注释,配置我们需要的模块就可以了

  • 文件上传,像下面的例子,我们配置好注解,在调用方法之前设置好相应的对象就行了。
/**
     * 单张图片上传
     * retrofit 2.0的上传和以前略有不同,需要借助@Multipart注解、@Part和MultipartBody实现。
     *
     * @param url
     * @param file
     * @return
     */
    @Multipart
    @POST("{url}")
    Call> upload(@Path("url") String url, @Part MultipartBody.Part file);
    /**
     * 多张图片上传
     *
     * @param map
     * @return
     */
    @Multipart
    @POST("upload/upload")
    Call> upload(@PartMap Map map);

    /**
     * 图文混传
     *
     * @param post
     * @param map
     * @return
     */
    @Multipart
    @POST("")
    Call> register(@Body News post, @PartMap Map map);
    /**
     * 这里需要注意的是如果下载的文件较大,比如在10m以上,那么强烈建议你使用@Streaming进行注解,否则将会出现IO异常.
     *
     * @param fileUrl
     * @return
     */
    @Streaming
    @GET
    Observable> downloadPicture2(@Url String fileUrl);

以上接口实例出自 作者:wo叫天然呆
链接:https://www.jianshu.com/p/73216939806a
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Okhttp3+Retrofit2+RxJava2的基本使用,我们基本都了解完了,很简单的对吧!
上面用到的一些代码戳这里

拼搏在技术道路上的一只小白And成长之路

你可能感兴趣的:(Android---网络编程)