Retrofit2是
square公司出品的一個網絡請求庫,網上有很多相關的介紹。我很久以前都想去研究了,但一直都有各種事情耽擱,現在就讓我們一起去捋一捋,這篇主要講解
Retrofit2與
RxJava的基本用法。
get
請求post
請求文件上傳
文件下載
開啟日誌攔截
與RxJava結合使用
什麽是Retrofit2
官網是這麽介紹的:
Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to define how requests are made。
我翻譯的可能不準確,他的大概意思是說:Retrofit 是一個 java 接口類,以註解的方式用於 HTTP 網絡請求。那下面我們一起來看看是怎麽使用的?
使用前的配置
build.gradle 的 dependencies 添加:
compile 'com.Google.code.gson:gson:2.3.1' compile 'com.squareup.retrofit2:retrofit:2.0.0' compile 'com.squareup.retrofit2:converter-gson:2.0.0' compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
獲取Retrofit實例
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://plus31.366ec.net/") .addConverterFactory(GsonConverterFactory.create()) .build();
需要註意的是
baseUrl添加的是地址的主域名。
申明RestService接口類
public interface RestService { @GET("/Route.axd?method=vast.Store.manager.list") Call<ResponseBody> getManagerData(@Query("StoreId") int id); }
@GET包含的是請求地址,是主域名之後的地址。舉個例子,請求的
全地址:
http://plus31.366ec.net/Route.axd?method=vast.Store.manager.list,
主域名為:
http://plus31.366ec.net/
@GET包含的地址為:
/Route.axd?method=vast.Store.manager.list
這樣就完成了一個簡單的
@GET封裝。
創建RestClient類
public class RestClient { private Retrofit mRetrofit; private static final String BASE_URL = "http://plus31.366ec.net/"; private RestService mService; //構造方法 public RestClient() { mRetrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); mService = mRetrofit.create(RestService.class); } public RestService getRectService() { if (mService != null) { return mService; } return null; } }
這樣就生成了一個簡單的代理類,然後就可以進行相應請求了。
Get請求
public class SimpleGetActivity extends AppCompatActivity { private Button btnGet; private TextView tvResult; private RestClient mRestClient; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simple_get); btnGet = (Button) findViewById(R.id.btn_get); tvResult = (TextView) findViewById(R.id.tv_result); btnGet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //獲取實例 mRestClient = new RestClient(); Call<ResponseBody> responseBodyCall = mRestClient.getRectService().getManagerData(49); //調用回調接口 responseBodyCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { tvResult.setText(response.body().string()); } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } }); } }); } }
一起來看看效果:
分析返回的
json數據,包含集合,那麽我們可以進一步對接口返回值進行數據的封裝。
BaseResponse類
public class BaseResponse<T> { @SerializedName("data") public List<T> managerList; @SerializedName("code") public int code; @SerializedName("message") public String message; }
註意:
BaseResponse類的字段,根據自己返回
json數據新增或者刪除。
根據返回的
json集合,那麽我們肯定有個實體類了。
Manager類
public class Manager { public int Id; public String UserName; }
Manager類你可以替換成你自己的實體類。
Get的進一步封裝
@GET("/Route.axd?method=vast.Store.manager.list")
Call<BaseResponse<Manager>> getManagerDatas(@Query("StoreId") int id);
註意:我們這裏對方法的返回值進行了一個修改
Call<BaseResponse<Manager>>
來看看封裝後的
Activity類:
public class GetActivity extends AppCompatActivity { private Button btnGet; private RestClient mRestClient; private RecyclerView mRecyclerView; private BaseRecyclerAdapter<Manager> mAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_get); btnGet = (Button) findViewById(R.id.btn_get); mRecyclerView = (RecyclerView) findViewById(R.id.rv); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); btnGet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //獲取實例 mRestClient = new RestClient(); Call<BaseResponse<Manager>> baseResponseCall = mRestClient.getRectService().getManagerDatas(49); baseResponseCall.enqueue(new Callback<BaseResponse<Manager>>() { @Override public void onResponse(Call<BaseResponse<Manager>> call, Response<BaseResponse<Manager>> response) { //獲取返回的集合數據 //response.body().managerList mAdapter = new BaseRecyclerAdapter<Manager>(GetActivity.this, response.body().managerList, R.layout.rv_item) { @Override protected void convert(BaseViewHolder helper, Manager item) { helper.setText(R.id.tv_item_text, item.UserName); } }; mRecyclerView.setAdapter(mAdapter); } @Override public void onFailure(Call<BaseResponse<Manager>> call, Throwable t) { } }); } }); } }
來看看效果:
Get常用技巧
HashMap組裝參數:
@GET("/Route.axd?method=vast.Store.manager.list") Call<BaseResponse<Manager>> getManagerDatas(@QueryMap HashMap<String, String> hm);
Get請求就講到這裏了,下面一起來看看
Post請求。
Post請求
@FormUrlEncoded
@POST("/Route.axd?method=vast.Store.manager.list")
Call<BaseResponse<Manager>> postManagerDatas(@Field("StoreId") int id);
@Field("StoreId") int id可以替換
@Body,
@Body你可以傳入
HashMap、實體
beans等對象。
註意:以
@Body上傳參數,會默認加上
Content-Type: application/json;
charset=UTF-8的請求頭,即以
JSON格式請求,再以
JSON格式響應。
單個文件上傳
@Multipart
@POST("/UploadProduct.axd")
Call<ResponseBody> uploadSimpleFile(@Part MultipartBody.Part file);
文件上傳稍微復雜點,具體請看以下代碼:
File file = new File("/sdcard/", "a.xlxs"); //file RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); //監聽上傳進度 CountingRequestBody countingRequestBody = new CountingRequestBody(requestFile, new CountingRequestBody.Liste @Override public void onRequestProgress(long bytesWritten, long contentLength) { tvFile.setText("上傳進度:" + contentLength + ":" + bytesWritten); } }); MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(),countingRequestBody); mRestClient = new RestClient("http://192.168.4.111:686/"); Call<ResponseBody> responseBodyCall = mRestClient.getRectService().uploadSimpleFile(body); responseBodyCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { tvFile.setText("上傳成功"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { tvFile.setText(t.toString()); } });
看看效果圖:
多文件上傳
@Multipart
@POST("/HpWens/ProgressDemos/")
Call<ResponseBody> uploads(@PartMap Map<String, RequestBody> params);
private void initData() { //保證文件按順序上傳 使用LinkedHashMap params = new LinkedHashMap<>(); File file1 = new File("/sdcard/", "a.xlxs"); final RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1); //監聽上傳進度 CountingRequestBody countingRequestBody1 = new CountingRequestBody(requestBody1, new CountingRequestBody.Listener() { @Override public void onRequestProgress(long bytesWritten, long contentLength) { tvFile1.setText("上傳進度:" + contentLength + ":" + bytesWritten); } }); params.put("file\";filename=\"" + file1.getName(), countingRequestBody1); File file2 = new File("/sdcard/", "a.xlxs"); RequestBody requestBody2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2); //監聽上傳進度 CountingRequestBody countingRequestBody2 = new CountingRequestBody(requestBody2, new CountingRequestBody.Listener() { @Override public void onRequestProgress(long bytesWritten, long contentLength) { tvFile2.setText("上傳進度:" + contentLength + ":" + bytesWritten); } }); params.put("file\";filename=\"" + file2.getName(), countingRequestBody2); mRestClient = new RestClient("http://192.168.4.111:686/"); btnUpload.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Call<ResponseBody> responseBodyCall = mRestClient.getRectService().uploadMultiFiles(params); responseBodyCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { tvFile1.setText("上傳成功"); tvFile2.setText("上傳成功"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } }); } }); }
在文章的後面我會附上源碼,這裏我就不在貼圖了,具體請看demo
文件下載
@Streaming
@GET("/image/h%3D360/sign=86aee1fbf1deb48fe469a7d8c01e3aef/{filename}")
Call<ResponseBody> downFile(@Path("filename") String fileName);
處理方式基本和上面幾種差不多:
public class DownFileActivity extends AppCompatActivity { private ImageView iv; private Button btnDown; private RestClient mRestClient; private String fileName; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_down_file); iv = (ImageView) findViewById(R.id.iv); btnDown = (Button) findViewById(R.id.btn_down); mRestClient = new RestClient("http://d.hiphotos.baidu.com/"); fileName = "b812c8fcc3cec3fd8757dcefd488d43f8794273a.jpg"; btnDown.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Call<ResponseBody> userCall = mRestClient.getRectService().downFile(fileName); userCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { iv.setImageBitmap(BitmapFactory.decodeStream(response.body().byteStream())); //saveFile(response.body().byteStream()); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { } }); } }); } public void saveFile(InputStream is){ try { String fn = Environment.getExternalStorageDirectory() + "/" + fileName; FileOutputStream fos = new FileOutputStream(fn); byte[] buf = new byte[1024]; int len; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } is.close(); fos.close(); } catch (Exception ex) { } } }
效果一覽:
開啟OKHttp的日誌攔截
開啟日誌後,會記錄request和response的相關信息,非常實用,也非常強大,不知道是否是編碼格式,我下載圖片打印的全是亂碼。
public void initRestClint(String baseUrl) { logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); httpClient.addInterceptor(logging); mRetrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(httpClient.build()) .build(); mService = mRetrofit.create(RestService.class); }
類似這樣的
logcat日誌:
Retrofit2與RxJava結合使用
添加庫:
compile 'io.reactivex:rxandroid:1.1.0' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
添加
addCallAdapterFactory(RxJavaCallAdapterFactory.create())到
Retrofit.Builder中:
mRetrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(httpClient.build()) .build();
那麽我們結合
RxJava一起使用呢,下面我們一起來看一看:
@GET("/Route.axd?method=vast.Store.manager.list")
Observable<BaseResponse<Manager>> getManagers(@Query("StoreId") int id);
通過我們的觀察是不是發現只有返回值發送了變化,
Observable類型。
//獲取實例 mRestClient = new RestClient(); mRestClient.getRectService().getManagers(49) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<BaseResponse<Manager>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(BaseResponse<Manager> managerBaseResponse) { } });
RxJava支持鏈式寫法,可以處理一些很復雜的問題。
源碼地址
如果對你有所幫助,還請stat,歡迎加入478720016 來幫助更多的人
Tags: interface declared methods 上傳文件 public
文章來源: