Retrofit2與RxJava用法解析

分類:IT技術 時間:2016-10-16

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) {

                    }
                });
            }
        });
    }
}

一起來看看效果:

retro


分析返回的

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) {

                    }
                });

            }
        });
    }
}

來看看效果:

retro


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());
        }
    });

看看效果圖:

retro

多文件上傳

@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) {

        }
    }
}

效果一覽:

retro


開啟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
日誌:

retro

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

文章來源:


ads
ads

相關文章
ads

相關文章

ad