retrofit2 使用教程 及 Android 网络架构搭建 (原创)

squareup 推出 retrofit2 已经有一段时间了,现在的版本比较稳定,没有什么大坑了。网络上的教程要么太简单,只是个Demo;要么有些落时,要么复用性比较差,所以自己写个教程,供大家参考。代码已上传至 https://github.com/Alex9Xu/RetrofitDemo


1. 首先在build.gradle引入依赖

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'

注意,这里的 logging 用于输出网络交互的Log,对于开发调试极其有用。之前retrofit2因为不能输出Log被人嫌弃了很久,各高手实现了几种打印Log的方式,现在总算有官方的了。


2. 这是工具类

package com.alex9xu.hello.net;

import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import com.alex9xu.hello.config.AppConfigInterface;
import com.alex9xu.hello.utils.LogHelper;

import java.io.IOException;
import java.lang.ref.WeakReference;

/**
 * Created by Alex9Xu@hotmail.com on 2016/7/13
 */
public class RetrofitBase {
    private static final String TAG = "RetrofitBase";

    private static Retrofit mRetrofit;
//    private static Dialog mLoadingDialog;
    private static WeakReference<Context> mContextRef;

    public static Retrofit retrofit() {
        if (mRetrofit == null) {
            OkHttpClient client;

            // Notice: The only differ of debug is: HttpLoggingInterceptor
            // Common Params: "version" and "server_call_version" will in every request
            if(!AppConfigInterface.isDebug) {
                client = new OkHttpClient.Builder()
                        .addInterceptor(new Interceptor() {
                            @Override
                            public Response intercept(Chain chain) throws IOException {
                                Request original = chain.request();
                                HttpUrl originalHttpUrl = original.url();
                                HttpUrl url = originalHttpUrl.newBuilder()
                                        .addQueryParameter("call_version", AppConfigInterface.TO_SERVER_VERSION)
                                        .addQueryParameter("deviceType", AppConfigInterface.DEVICE_TYPE)
                                        .build();
                                // Request customization: add request headers
                                Request.Builder requestBuilder = original.newBuilder()
                                        .addHeader("user-agent", "android")
                                        .url(url);
                                Request request = requestBuilder.build();
                                return chain.proceed(request);
                            }
                        })
                        .build();
            } else {
                HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
                logging.setLevel(HttpLoggingInterceptor.Level.BODY);
                client = new OkHttpClient.Builder()
                        .addInterceptor(logging)
                        .addInterceptor(new Interceptor() {
                            @Override
                            public Response intercept(Chain chain) throws IOException {
                                Request original = chain.request();
                                HttpUrl originalHttpUrl = original.url();
                                HttpUrl url = originalHttpUrl.newBuilder()
                                        .addQueryParameter("version", AppConfigInterface.TO_SERVER_VERSION)
                                        .addQueryParameter("deviceType", AppConfigInterface.DEVICE_TYPE)
                                        .build();
                                // Request customization: add request headers
                                Request.Builder requestBuilder = original.newBuilder()
                                        .addHeader("user-agent", "android")
                                        .url(url);
                                Request request = requestBuilder.build();
                                return chain.proceed(request);
                            }
                        })
                        .build();
            }

            mRetrofit = new Retrofit.Builder()
                    .baseUrl(AppConfigInterface.BASE_COM_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build();
        }
        return mRetrofit;
    }

    // Encapsulation Request and Response
    public static <T> void AddToEnqueue(Call<T> baseCall, Context context, boolean isShowDlg,
                                        final NetRequestListener listener) {
        mContextRef = new WeakReference<>(context);
//        if(isShowDlg && null == mLoadingDialog && null != mContextRef.get()) {
//            mLoadingDialog = DialogUtil.showLoginDialog(mContextRef.get());
//            mLoadingDialog.getWindow().setBackgroundDrawable(new BitmapDrawable());
//        }
//        if(isShowDlg) {
//            mLoadingDialog.show();
//        }

        baseCall.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, retrofit2.Response<T> response) {
                LogHelper.d(TAG, "toEnqueue, onResponse:");
                if (null != response.body()) {
                    if(response.code() == 200) {
                        LogHelper.d(TAG, "toEnqueue, onResponse Suc");
//                        if(null != mLoadingDialog) {
//                            mLoadingDialog.dismiss();
//                        }
                        listener.onRequestSuc(response.code(), response);
                    } else {
                        LogHelper.d(TAG, "toEnqueue, onResponse Fail:" + response.code());
//                        if(null != mLoadingDialog) {
//                            mLoadingDialog.dismiss();
//                        }
                        listener.onRequestFail(response.code(), response.message());
                    }
                } else {
                    LogHelper.d(TAG, "toEnqueue, onResponse Fail");
//                    if(null != mLoadingDialog) {
//                        mLoadingDialog.dismiss();
//                    }
                    listener.onRequestFail(response.code(), response.message());
                }
            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {
                LogHelper.d(TAG, "toEnqueue, onFailure Fail");
//                if(null != mLoadingDialog) {
//                    mLoadingDialog.dismiss();
//                }
                listener.onRequestFail(AppConfigInterface.RESULT_FAIL_UNKNOW, null);
            }
        });
    }

    public static void stopLoadingDlg(Context context) {
//        if(null != mContextRef && context == mContextRef.get() && null != mLoadingDialog) {
//            mLoadingDialog.dismiss();
//            mLoadingDialog = null;
//        }
    }

}
 

讲解一下:

(1) 通过 addInterceptor 实现的打印日志及加入多个公共参数功能。

(2) 除了含有 HttpLoggingInterceptor 外,测试的和正式的,没有任何区别。通过全局变量控制是否为正式环境,如果是正式环境则不输出网络交互相关的Log。

(3) 可以通过 addQueryParameter("deviceType", "0") 的形式加入多个公共参数,这样所有的请求都会带该参数。

(4) 这里 BASE_COM_URL 是 http://test.hello.com/ 的形式。

3. 使用方式:

(1) 先写接口

package com.alex9xu.hello.net.apis;

import android.support.v4.util.ArrayMap;
import com.alex9xu.hello.config.AppConfigInterface;
import com.alex9xu.hello.model.WeatherResult;

import retrofit2.Call;

import retrofit2.http.GET;
import retrofit2.http.QueryMap;

/**
 * Created by Alex9Xu@hotmail.com on 2016/7/14
 */

public interface CityWeatherApi {
    @GET(AppConfigInterface.GET_WEATHER)
    Call<WeatherResult> getClassify(@QueryMap ArrayMap<String,String> paramMap);
}
 

这里通过Post提交参数,参数存储在Map里,可以添加多组参数。注意,我使用了ArrayMap,这是Android里特有的一种形式,内存占用只有HashMap的十分之一左右。

String CLASSIFYLIST = "query/classify.html";


(2) 再写返回值结构

package com.alex9xu.hello.model.Entity;

/**
 * Created by Alex9Xu@hotmail.com on 2016/7/18
 */
public class Weatherinfo {
    private String city;
    private String cityid;
    private String temp;
    private String WD;
    private String WS;
    private String SD;
    private String WSE;
    private String time;
    private String isRadar;
    private String Radar;
    private String njd;
    private String qy;

    public String getCity() {
        return city;
    }

    public String getTemp() {
        return temp;
    }
}


package com.alex9xu.hello.model;

import com.alex9xu.hello.model.Entity.Weatherinfo;

/**
 * Created by Alex9Xu@hotmail.com on 2016/7/18
 */
public class WeatherResult {

    private Weatherinfo weatherinfo;

    public Weatherinfo getWeatherinfo() {
        return weatherinfo;
    }

}

返回的数据写成如上形式,以利于复用。


(3) 调用

import com.alex9xu.test.model.ClassifyListResult;
import com.alex9xu.test.model.entity.ClassfiyBean;
import com.alex9xu.test.net.ClassifyApi;
import com.alex9xu.test.net.RetrofitBase;
/**
 * Created by Alex9Xu@hotmail.com on 2016/7/14
 */

public class MainActivity extends BaseActivity {
    // Note: make all the Activities extends BaseActivity to manage
    private static final String TAG = "MainActivity";

    private TextView mTvwShowInfo;
    private Call<WeatherResult> mWeatherCall;
private void getData() {
    // Notice: ArrayMap requires less memory in Android compare with HashMap (about 10%)
    CityWeatherApi classifyApi = RetrofitBase.retrofit().create(CityWeatherApi.class);
    ArrayMap<String,String> paramMap = new ArrayMap<>();
    paramMap.put("sortType", "1");
    paramMap.put("uid", "654321");
    mWeatherCall = classifyApi.getClassify(paramMap);

    RetrofitBase.AddToEnqueue(mWeatherCall, MainActivity.this, true, new NetRequestListener() {
        @Override
        public void onRequestSuc(int code, Response response) {
            LogHelper.d(TAG, "onRequestSuc");
            Response<WeatherResult> resultResponse = response;
            if(null != resultResponse.body().getWeatherinfo()) {
                Weatherinfo info  = resultResponse.body().getWeatherinfo();
                StringBuilder strBld = new StringBuilder();
                strBld.append(info.getCity());
                strBld.append(getString(R.string.temperature));
                strBld.append(getString(R.string.colon));
                strBld.append(info.getTemp());
                mTvwShowInfo.setText(strBld.toString());
            }
        }

        @Override
        public void onRequestFail(int code, String reason) {
            LogHelper.d(TAG, "onRequestFail: " + code + ", " + reason);
        }
    });
}

@Override
protected void onStop() {
    super.onStop();
    // Notice: If the web operate is to update UI, you can cancel it when onStop
    mWeatherCall.cancel();
}
...


讲解:会拼接成 https://test.hello.com/query/classify.html?uid=654321&version=1.0&Id=123456&deviceType=0 ,注意,其中两项是公共参数。


好了,这样就可以正常运行了。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值