Retrofit 2.0 + OkHttp 3.0+JSON网络请求

来源:互联网 发布:数据交易是指什么 编辑:程序博客网 时间:2024/06/06 18:34

Retrofit 和 OkHttp 都是伟大的 Square 公司开源的伟大项目。我从 2014 年便在同事 ionull 的推荐带领下,使用这个网络库组合以及 RxJava,真是极大改善 Android 开发体验的好东西。前段时间也是从 Retrofit 1.9 升级到 2.0 beta 4 版本,从 OkHttp 2.+ 版本升级到  3.0.1 版本。这两者在各自的这两个大版本升级中,都改变了不少,使得原本的代码都需要进行一些修改才能使用,我也是稍微摸索了几下,如今大致摸清,把一些基础配置,比如设置 Json 转换器、Rx Java 适配器、设置 Debug Log 模式、设置超时、错误重连,以及配置 Access token Interceptor 等等一些内容,分享一下。

引入依赖:

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'compile 'com.squareup.okhttp3:okhttp:3.0.1'compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'

先说 OkHttp 3.0 的配置,3.0 使用层面上的主要改变是,由原本的 okHttp 对象直接各种 set 进行配置改为 Builder 配置模式,所以原本对应的方法应该到 OkHttpClient.Builder 类对象下寻找。我的一些常用配置如下:

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);OkHttpClient client = new OkHttpClient.Builder()        .addInterceptor(interceptor)        .retryOnConnectionFailure(true)        .connectTimeout(15, TimeUnit.SECONDS)        .addNetworkInterceptor(mTokenInterceptor)        .build();


解释:

HttpLoggingInterceptor 是一个拦截器,用于输出网络请求和结果的 Log,可以配置 level 为 BASIC / HEADERS / BODY,都很好理解,对应的是原来 retrofit 的 set log level 方法,现在 retrofit 已经没有这个方法了,所以只能到 OkHttp 这边来配置,并且 BODY 对应原来到 FULL.

retryOnConnectionFailure 方法为设置出现错误进行重新连接。

connectTimeout 设置超时时间

addNetworkInterceptor 让所有网络请求都附上你的拦截器,我这里设置了一个 token 拦截器,就是在所有网络请求的 header 加上 token 参数,下面会稍微讲一下这个内容。

让所有网络请求都附上你的拦截器:

Interceptor mTokenInterceptor = new Interceptor() {    @Override public Response intercept(Chain chain) throws IOException {        Request originalRequest = chain.request();        if (Your.sToken == null || alreadyHasAuthorizationHeader(originalRequest)) {            return chain.proceed(originalRequest);        }        Request authorised = originalRequest.newBuilder()            .header("Authorization", Your.sToken)            .build();        return chain.proceed(authorised);    }};

解释:

那个 if 判断意思是,如果你的 token 是空的,就是还没有请求到 token,比如对于登陆请求,是没有 token 的,只有等到登陆之后才有 token,这时候就不进行附着上 token。另外,如果你的请求中已经带有验证 header 了,比如你手动设置了一个另外的 token,那么也不需要再附着这一个 token.

header 的 key 通常是 Authorization,如果你的不是这个,可以修改。

如果你需要在遇到诸如 401 Not Authorised 的时候进行刷新 token,可以使用 Authenticator,这是一个专门设计用于当验证出现错误的时候,进行询问获取处理的拦截器:

Authenticator mAuthenticator = new Authenticator() {    @Override public Request authenticate(Route route, Response response)            throws IOException {        Your.sToken = service.refreshToken();        return response.request().newBuilder()                       .addHeader("Authorization", newAccessToken)                       .build();            }}

然后,对于以上的两个拦截器,分别使用 OkHttpClient.Builder 对象的 addNetworkInterceptor(mTokenInterceptor) 和 authenticator(mAuthenticator) 即可。

Retrofit:

对于 Retrofit,我的配置是:

Retrofit retrofit = new Retrofit.Builder()        .baseUrl(AppConfig.BASE_URL)        .client(client)        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())        .addConverterFactory(GsonConverterFactory.create(gson))        .build();service = retrofit.create(YourApi.class);

解释:

baseUrl: 原来的 setEndPoint 方法变成了 baseUrl

client 即上面的 OkHttp3 对象

addCallAdapterFactory 增加 RxJava 适配器

addConverterFactory 增加 Gson 转换器

   具体实现一个Demo

利用 Retrofit2.0okhttp+Json解析百度名人名言:

http://apistore.baidu.com/apiworks/servicedetail/1756.html


1.分四个步骤

 1.创建Retrofit对象

2. 创建访问API的请求

3 .发送请求

4.处理结果 

首先解决JAR包的问题

dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:23.2.0'    compile 'com.squareup.okhttp3:okhttp:3.2.0'    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'    compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3'    compile 'com.android.support:support-annotations:23.1.1'    compile 'com.android.support:design:23.1.0'}


还有配置文件

<uses-permission android:name="android.permission.INTERNET" />


根据官方文档我们需要创建一个接口,并且选择请求方式,返回一个Call对象/** * Created by gaomin on 2016/4/14. */public interface FamousService {    @GET("avatardata/mingrenmingyan/lookup")    Call<FamousInfo>getFamousResult(@Header("apiKey") String apiKey ,  //请求秘钥参数                                      @Query("keyword") String keyword ,//请求关键字                                      @Query("page") String page,       //请求页数                                      @Query("rows") String rows);       //请求记录条数} 现在接口定义好了,我们来* 定义Retrofit 网络接口服务的包装类 *:   /** * Created by gaomin on 2016/4/14. * 网络接口包装类建议使用单例模式 * 并且可以使用双重加锁代码块,避免多线程和效率 */public class RetrofitWrapper {    private static volatile RetrofitWrapper sInstance;    private Retrofit retrofit;    private RetrofitWrapper(){        retrofit = new Retrofit.Builder()                .baseUrl(GMUrl.BASEURL)      //访问主机地址                .addConverterFactory(GsonConverterFactory.create())  //解析方式                .build();    }    public static RetrofitWrapper getInstance(){        if(null == sInstance){            synchronized (RetrofitWrapper.class){                if(null == sInstance){                    sInstance = new RetrofitWrapper();                }            }        }        return sInstance;    };    public <T> T create(final Class<T> service){        return retrofit.create(service);    }} 网络服务的包装类定义好了之后,在定义一个访问的Modelpackage com.gaomin.retrofitokhttpdemo.Model;import com.gaomin.retrofitokhttpdemo.RetrofitWrapper;import com.gaomin.retrofitokhttpdemo.bean.FamousInfo;import com.gaomin.retrofitokhttpdemo.bean.FamousInfoReq;import com.gaomin.retrofitokhttpdemo.serviceAPi.FamousService;import retrofit2.Call;/** * Created by gaomin on 2016/4/14. * 这里采用懒汉式单例模式 * 不考虑多线程方面问题 */public class FamousInfoModel {    private static FamousInfoModel sInstance;    private FamousService mFamousService;    public static FamousInfoModel getInstance(){        if(null == sInstance){            sInstance = new FamousInfoModel();        }        return sInstance;    }    private FamousInfoModel(){        mFamousService = (FamousService) RetrofitWrapper.getInstance().create(FamousService.class);    }    /**     * 查询名人名言     *     * @param famousInfoReq     * @return     */    public  Call<FamousInfo>  queryLookUp(FamousInfoReq famousInfoReq){        Call<FamousInfo> infoCall = mFamousService.getFamousResult(famousInfoReq.apiKey,                famousInfoReq.keyword,                famousInfoReq.page,                famousInfoReq.rows);        return infoCall;    }}构建好接口以后,可以使用了!package com.gaomin.retrofitokhttpdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.EditText;import android.widget.ImageButton;import android.widget.ListView;import android.widget.TextView;import com.gaomin.retrofitokhttpdemo.Model.FamousInfoModel;import com.gaomin.retrofitokhttpdemo.bean.FamousInfo;import com.gaomin.retrofitokhttpdemo.bean.FamousInfoReq;import java.util.ArrayList;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;public class MainActivity extends AppCompatActivity {    ArrayList<FamousInfo.ResultEntity> entity;    private ListView mListView;    public final String TAG=this.getClass().getName();    private FamousInfoModel famousInfoModel;    private EditText mEditKeyWord;    private ImageButton mSerachBtn;    private TextView mTxtContent;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        famousInfoModel =FamousInfoModel.getInstance();        entity = new ArrayList<FamousInfo.ResultEntity>();        initView();        initParams();        initEvent();    }    /**     * 初始化View     */    private void initView() {        mEditKeyWord = (EditText) findViewById(R.id.edit_keyword);        mSerachBtn = (ImageButton) findViewById(R.id.button_search);        mListView = (ListView)findViewById(R.id.mListView);    }    /**     * 初始化参数     */    private FamousInfoReq initParams() {        FamousInfoReq mFamousInfoReq=null;        mFamousInfoReq= new FamousInfoReq();        mFamousInfoReq.apiKey= GMUrl.APIKEY;        mFamousInfoReq.keyword =mEditKeyWord.getText().toString();        mFamousInfoReq.page=3;        mFamousInfoReq.rows=30;        return  mFamousInfoReq;    }    // 获取事件    private void initEvent() {        mSerachBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //创建访问的API请求                Call<FamousInfo> callFamous= famousInfoModel.queryLookUp(initParams());                //发送请求                callFamous.enqueue(new Callback<FamousInfo>() {                    @Override                    public void onResponse(Call<FamousInfo> call, Response<FamousInfo> response) {                        if(response.isSuccess()){                            FamousInfo result = response.body();                            if(result!=null){                                entity = (ArrayList<FamousInfo.ResultEntity>) result.getResult();                                mListView.setAdapter(new MyAdapter(entity));                            }                        }                    }                    @Override                    public void onFailure(Call<FamousInfo> call, Throwable t) {                    }                });            }        });    }    class MyAdapter extends BaseAdapter{        private ArrayList entityBAArrayList;        public MyAdapter(ArrayList a){            entityBAArrayList = a;        }        @Override        public int getCount() {            return entityBAArrayList.size();        }        @Override        public Object getItem(int position) {            return position;        }        @Override        public long getItemId(int position) {            return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {            ViewHolder viewHolder =null;            if(null == convertView){                viewHolder = new ViewHolder();                convertView = getLayoutInflater().inflate(R.layout.listview_item,null);                viewHolder.titleTV = (TextView)convertView.findViewById(R.id.titleTV);                viewHolder.contentTV = (TextView)convertView.findViewById(R.id.contentTV);                convertView.setTag(viewHolder);            }else {                viewHolder = (ViewHolder)convertView.getTag();            }            viewHolder.titleTV.setText("名人--"+entity.get(position).getFamous_name());            viewHolder.contentTV.setText(entity.get(position).getFamous_saying());            return convertView;        }    }    class ViewHolder{        private TextView titleTV;        private TextView contentTV;    }}
javabean对象就不给出来了,自己看具体的JSON写吧,或者用工具解析

3 0
原创粉丝点击