Retrofit2---网络交互的艺术

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

Retrofit是啥

A type-safe HTTP client for Android and Java
翻译:Android和Java使用类型安全的Http客户端

Retrofit的前世今生

Http客户端用来做网络访问,网络访问,对绝大多数应用来说是一个基础功能
我们来简单回顾下网络访问框架的发展史:
1. HttpUrlConnection和HttpClient。Android2.1时代,还没有什么框架流行,请求网络都用这个。HttpUrlConnection刚出来的时候Bug巨多,比如说—对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。后面一直有人在维护,在Android 2.3版本的时候,谷歌加入了更加透明化的响应压缩。 在Android 4.0版本中,又添加了一些响应的缓存机制。HttpClient是Apache的,出来的时候比较稳定,但是Android官方对它一直都没怎么维护,甚至从Android5.1版本开始已经把它从SDK移除了,如果还在使用的同学需要自己去手动导入Apache的包。
2. android-async-http。随后又出现了async-http,它在一些反面做了升级,实现了简单的封装,框架雏形。比如:

 1. 异步请求能力,匿名回调处理Response
 2. 内部使用线程池来处理并发请求,线程重用提高效率
 3. Http请求,发生再异步线程

3. Afindl,Xutils。包含网络访问框架,图片加载,数据库,控件绑定框架合成的一系列框架的集合框架。当年他们可是风靡一时,这个很好、很中国。就像小时候玩”学习机”,小霸王其乐无穷时代,4合一、8合一、99合一的赶脚。回过头看,这种框架特别符合中国人的思维方式—极致的使用主义,包含所有,中庸之道。但是兼顾太多,维护框架的人精力又是有限的,很容易就顾此失彼,慢慢的。绑定控件被ButterKnife,Dragger替代;图片加载慢慢的被ImageLoader替代,后来又被Picasso、Glide、Fresco替代;ORM数据库被GreenDao、ORMLite替代;网络–Volley替代;
4. Volley,不可否认Volley是一个出色的网络框架Volley源码解析,拓展性强,设计优雅。
5. OkHttp,Volley虽好但是奈何不住没人维护啊,直接再应用层使用看着臃肿,要自己再封装一次。Volley 默认根据 Android 系统版本使用不同的 Http 传输协议实现.在 Android 3.0 以上 Volley 使用 ApacheHttpStack 作为传输协议, 在2.3 及以下使用 HttpURLConnection 作为传输层协议。注意:3.0以上使用ApacheHttpStack作为传输协议这句话,谷歌从Android5.1开始已经把Apache的东西从SDK中移除了,后面就产生了问题。有很多文章说使用OkHttp+Volley联合开发,最开始看到的时候感觉很迷糊,有了OKHttp干嘛还要加上Volley做网络访问。后面想想应该是这么回事:老项目使用了Volley框架,但是传输协议ApacheHttpStack别人干掉了,所以添加OkHttp框架来做传输就行了,以前的代码不用再修改。
当然OkHttp 是 Square 公司开源的一个 HTTP 网络框架,广受好评。

好了,闲话扯得够多了,步入我们的正题—Retrofit

Retrofit和OkHttp的关系

从字面上理解Retrofit翻译为—改进、改装、对…作样式翻新
这里写图片描述
同样是Square公司出品,同样是用作Http Client,Retrofit后于OkHttp,这个翻新的对象明显就是OkHttp了。
当然并不是说就直接覆盖替换了OkHttp,相反OkHttp的功能实现和架构还是很漂亮的。从Retrofit2.0开始内置OkHttp,如果把OkHttp比作一间房子,Retrofit更像是在给房子做装修,让房间变得更好看,没宜居,至于底层的连接、通信、重试这些Retrofit都不关心,交给OkHttp去完成就好。

这里写图片描述
总之:

  1. OkHttp专注和服务层Api打交道,提供更稳定可靠的连接
  2. Retrofit专注和App打交道,提供更友好,易懂易维护的访问方式

为啥说Retrofit写得代码像艺术

多说无益,show me the code
例如我们要实现如下展示的功能:
这里写图片描述

不用Retrofit我们怎么写的代码

步骤:
1. 需要一个服务端Api
接口已准备好:

http://zhuangbi.info/search?q=牛逼

使用调试插件JSONOnlineViewer,可以直接再IDE里面调试

  1. 具备常用Get,Post…6种请求方式,配置请求参数
  2. 返回数据直接是格式化后的Json
  3. 可以查看请求头信息

这里写图片描述
2. 根据Api,数据格式编写实体类
使用插件GsonFormat,直接生成我们需要的实体— Android Studio使用—眼花缭乱的插件使用技巧
这里写图片描述
3. 配置Gradle文件
我们大概需要,网络访问—使用OkHttp,图片加载—Glide,因为返回的图片类型是gif,所以不考虑Picasso。需要一个V4包的加载组件android.support.v4.widget.SwipeRefreshLayout,一个V7包的RecyclerView—android.support.v7.widget.RecyclerView

    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:support-v4:23.2.1'
    compile 'com.android.support:support-v13:23.2.1'
    compile 'com.android.support:cardview-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0' //Gson
    compile 'com.github.bumptech.glide:glide:3.7.0'

4.配置HttpClient,访问网络

private void search() {
        mSwipeRefreshLayout.setRefreshing(true);
        Request request = new Request.Builder()
                .url("http://zhuangbi.info/search?q=" + getString(R.string.niubility))
                .build();

        call = mOkHttpClient.newCall(request);
        //异步执行
        call.enqueue(callBack);
    }

5.在回调方法中,通过Gson之类的工具解析为实体类

    Callback callBack = new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                Toast.makeText(App.getContext(), "", Toast.LENGTH_SHORT).show();
                mSwipeRefreshLayout.setRefreshing(false);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //解析json
                String resStr = response.body().string();
                Gson gson = new Gson();
                mDatas = gson.fromJson(resStr, new TypeToken<List<SearchImage>>() {
                }.getType());

                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //更新UI数据
                        mSwipeRefreshLayout.setRefreshing(false);
                        mAdapter.setDatas(mDatas);
                    }
                });

            }

        };
  1. 把实体类里面的数据显示到界面
public class SearchImageAdapter extends RecyclerView.Adapter {
    private List<SearchImage> mDatas;

    public void setDatas(List<SearchImage> datas) {
        mDatas = datas;
        notifyDataSetChanged();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_grid_search_image, parent, false);
        return new SearchImageViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        SearchImageViewHolder viewHolder = (SearchImageViewHolder) holder;
        SearchImage searchImage = mDatas.get(position);
        Glide.with(holder.itemView.getContext())
                .load(searchImage.image_url)
                .into(viewHolder.mIvShow);
        viewHolder.mTvDes.setText(searchImage.description);
    }

    @Override
    public int getItemCount() {
        return mDatas == null ? 0 : mDatas.size();
    }

    static class SearchImageViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.ivShow)
        ImageView mIvShow;
        @Bind(R.id.tvDes)
        TextView mTvDes;

        SearchImageViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}

使用Retrofit改写改写

  1. 配置Gradle
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'

2.配置API访问接口

public interface SearchApi {
    @GET("search")
    Observable<List<SearchImage>> search(@Query("q") String qTitle);
}

3.返回数据实体,已通过GsonFormat自动生成了

public class SearchImage {

    /**
     * id : 187
     * description : ????????????????????????????
     * path : i/2015-07-16-77b07ee973ffd5ab39015b927b04b3c3.jpg
     * size : 11007
     * width : 220
     * height : 94
     * created_at : 2015-07-16 16:03:06
     * updated_at : 2016-02-26 22:26:41
     * user_id : 1
     * permitted_at : 2016-02-26 22:26:41
     * disk : qiniu
     * hotpoint : 101
     * channel : null
     * upload_id : 167
     * image_url : http://zhuangbi.idagou.com/i/2016-02-26-b56183130c20ca2f8b6ec9c6616c1f95.jpg
     * file_size : 18.78 KB
     */

    private int id;
    private String description;
    private String path;
    private int size;
    private int width;
    private int height;
    private String created_at;
    private String updated_at;
    private int user_id;
    private String permitted_at;
    private String disk;
    private int hotpoint;
    private Object channel;
    private int upload_id;
    private String image_url;
    private String file_size;
    ...省略
  }

4.步入正题—请求数据

    public static SearchApi getSearchApi() {

        if (sSearchApi == null) {
            sSearchApi = new Retrofit.Builder()
                    .client(sOkHttpClient)
                    .baseUrl("http://zhuangbi.info/")
                    .addConverterFactory(sGsonConverterFactory)
                    .addCallAdapterFactory(sRxJavaCallAdapterFactory)
                    .build()
                    .create(SearchApi.class);
        }
        return sSearchApi;
    }
    private void search(String title) {

        Subscriber<List<SearchImage>> subscriber = new Subscriber<List<SearchImage>>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                mSwipeRefreshLayout.setRefreshing(false);
                Toast.makeText(App.getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNext(List<SearchImage> searchImages) {
                mSwipeRefreshLayout.setRefreshing(false);
                //显示数据
                mAdapter.setDatas(searchImages);
            }
        };
        mSubscription = NetWork.getSearchApi() //获取SearchApi 具备网络通信能力
                .search(title) //访问特定Api接口
                .subscribeOn(Schedulers.io())//指定在非UI线程访问,执行(被观察)事件
                .observeOn(AndroidSchedulers.mainThread())//指定在UI线程执行观察者(回调)结果
                .subscribe(subscriber);//观察者(回调)执行
    }

OK,以上就是Retrofit的简单使用。
代码下载:https://github.com/zhouruikevin/RxJavaSamples-master

猜你喜欢

转载自blog.csdn.net/zivensonice/article/details/51752734