squareup 推出 retrofit2 已經有一段時間了,如今的版本比較穩定,沒有什麼大坑了。網絡上的教程要麼太簡單,只是個Demo;要麼有些落時,要麼複用性比較差,因此本身寫個教程,供你們參考。代碼已上傳至 https://github.com/Alex9Xu/RetrofitDemohtml
1. 首先在build.gradle引入依賴java
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的方式,如今總算有官方的了。android
2. 這是工具類git
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;
// }
}
}
講解一下:github
(1) 經過 addInterceptor 實現的打印日誌及加入多個公共參數功能。web
(2) 除了含有 HttpLoggingInterceptor 外,測試的和正式的,沒有任何區別。經過全局變量控制是否爲正式環境,若是是正式環境則不輸出網絡交互相關的Log。api
(3) 能夠經過 addQueryParameter("deviceType", "0") 的形式加入多個公共參數,這樣全部的請求都會帶該參數。網絡
(4) 這裏 BASE_COM_URL 是 http://test.hello.com/ 的形式。app
3. 使用方式:less
(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);
}
這裏經過Get提交參數,參數存儲在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 ,注意,其中兩項是公共參數。
好了,這樣就能夠正常運行了。