Retrofit2
是square
公司出品的一個網絡請求庫,網上有不少相關的介紹。我好久之前都想去研究了,但一直都有各類事情耽擱,如今就讓咱們一塊兒去捋一捋,這篇主要講解Retrofit2
與RxJava
的基本用法。java
get
請求react
post
請求android
文件上傳git
文件下載github
開啓日誌攔截json
與RxJava結合使用網絡
官網是這麼介紹的:app
Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to define how requests are made。
我翻譯的可能不許確,他的大概意思是說:Retrofit 是一個 java 接口類,以註解的方式用於 HTTP 網絡請求。那下面咱們一塊兒來看看是怎麼使用的?ide
build.gradle 的 dependencies 添加:post
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 = new Retrofit.Builder() .baseUrl("http://plus31.366ec.net/") .addConverterFactory(GsonConverterFactory.create()) .build();
須要注意的是baseUrl
添加的是地址的主域名。
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
封裝。
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; } }
這樣就生成了一個簡單的代理類,而後就能夠進行相應請求了。
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
數據,包含集合,那麼咱們能夠進一步對接口返回值進行數據的封裝。
public class BaseResponse<T> { @SerializedName("data") public List<T> managerList; @SerializedName("code") public int code; @SerializedName("message") public String message; }
注意:BaseResponse
類的字段,根據本身返回json
數據新增或者刪除。
根據返回的json
集合,那麼咱們確定有個實體類了。
public class Manager { public int Id; public String UserName; }
Manager
類你能夠替換成你本身的實體類。
@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) { } }); } }); } }
來看看效果:
HashMap組裝參數
:
@GET("/Route.axd?method=vast.Store.manager.list") Call<BaseResponse<Manager>> getManagerDatas(@QueryMap HashMap<String, String> hm);
Get
請求就講到這裏了,下面一塊兒來看看 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) { } } }
效果一覽:
開啓日誌後,會記錄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
日誌:
添加庫:
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
支持鏈式寫法,能夠處理一些很複雜的問題。