最近在整理 Retrofit 和 Rxjava 的知識,前面幾篇文章分別整理了 Rxjava 和 Retrofit 現在就來整理一下 Retrofit 和 Rxjava的連用。知道了Retrofit 和 Rxjava 的單獨用法,連用其實很簡單。在Retrofit的基礎上改。
不一樣的地方有如下幾點:
第一,導的包不一樣
Retrofit中:
compile 'com.squareup.retrofit2:retrofit:2.2.0'// Retrofit庫
compile 'com.squareup.retrofit2:converter-gson:2.3.0'//返回的數據是json的,用到了gson解析
Retrofit 和 Rxjava連用中
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.x.y'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'//轉換器,請求結果轉換成Model
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//配合Rxjava 使用
第二,創建用於 描述網絡請求的接口的時候,方法返回值類型的改變。由Retrofit中的 Call<T> 變成了 Observable<T>,代碼如下:
Retrofit中:
/**
* 創建 用於描述網絡請求 的接口
* Retrofit將 Http請求 抽象成 Java接口:採用 註解 描述網絡請求參數 和配置網絡請求參數
*/
public interface ApiService {
//測試 get
@GET("ajax.php?a=fy&f=auto&t=auto&w=hello")
Call<ResponseInfo> testGet();
//測試 post
@POST("ajax.php?a=fy&f=auto&t=auto")
Call<ResponseInfo> testPost(@Query("w") String w);
//測試 下載文件
@Streaming
@GET
Call<ResponseBody> testDownload(@Url String fileUrl);
}
Retrofit 和 Rxjava連用中
/**
* 創建 用於描述網絡請求 的接口
* Retrofit將 Http請求 抽象成 Java接口:採用 註解 描述網絡請求參數 和配置網絡請求參數
*/
public interface ApiService {
//測試 get
@GET("ajax.php?a=fy&f=auto&t=auto&w=hello")
Observable<ResponseInfo> testGet();
//測試 post
@POST("ajax.php?a=fy&f=auto&t=auto")
Observable<ResponseInfo> testPost(@Query("w") String w);
//測試 下載文件
@Streaming
@GET
Observable<ResponseBody> testDownload(@Url String fileUrl);
}
第三,創建Retrofit實例的時候需要加上addCallAdapterFactory(RxJava2CallAdapterFactory.create()),代碼如下。
Retrofit中:
retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 設置 網絡請求 Url
.addConverterFactory(GsonConverterFactory.create()) //設置使用Gson解析(記得加入依賴)
.build();
Retrofit 和 Rxjava連用中:
retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 設置 網絡請求 Url
.addConverterFactory(GsonConverterFactory.create()) //設置使用Gson解析(記得加入依賴)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
第三,網絡請求方式不一樣
Retrofit中:
ApiService request = retrofit.create(ApiService.class);
Call<ResponseInfo> call = request.testGet();// 封裝請求
call.enqueue(new Callback<ResponseInfo>() {// 發送網絡請求(異步)
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {//主線程中調用
ResponseInfo body = response.body();
Log.i("gao", "測試 get body = " + body + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "測試GET= " + body.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {//主線程中調用
Log.i("gao", " testGet onFailure " + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
}
});
Retrofit 和 Rxjava連用中:
ApiService request = retrofit.create(ApiService.class);
Observable<ResponseInfo> observable = request.testGet();// 封裝請求
observable.subscribeOn(Schedulers.io())//網絡請求發生在 子線程
.observeOn(AndroidSchedulers.mainThread())//請求回調發生在 主線程
.subscribe(new Observer<ResponseInfo>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseInfo responseInfo) {
Log.i("gao", "測試 get body = " + responseInfo + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "測試GET= " + responseInfo.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
Log.i("gao", " testGet onFailure " + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {
}
});
demo中和上篇文章一樣寫了 怎麼請求 get post 和 怎麼下載文件,的方法,這裏是MainActivity的代碼。如果需要完整的代碼,在博客的最後有下載的方法。
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends Activity implements View.OnClickListener {
Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.testGet).setOnClickListener(this);
findViewById(R.id.testPost).setOnClickListener(this);
findViewById(R.id.testLoaddown).setOnClickListener(this);
// 創建Retrofit實例時需要通過Retrofit.Builder,並調用baseUrl方法設置URL。Retrofit2的baseUlr 必須以 /(斜線)結束,不然會拋出一個IllegalArgumentException
retrofit = new Retrofit.Builder()
.baseUrl("http://fy.iciba.com/") // 設置 網絡請求 Url
.addConverterFactory(GsonConverterFactory.create()) //設置使用Gson解析(記得加入依賴)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//動態獲取權限
AppPermission.isGrantExternalRW(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.testGet:
testGet();
break;
case R.id.testPost:
testPost("hello");
break;
case R.id.testLoaddown:
if (AppPermission.isGrantExternalRW(this)) {
String url = "http://imtt.dd.qq.com/16891/89E1C87A75EB3E1221F2CDE47A60824A.apk?fsname=com.snda.wifilocating_4.2.62_3192.apk&csr=1bbd";
testLoaddown(Environment.getExternalStorageDirectory() + "/ceshi.apk", url);
}
break;
}
}
public void testGet() {
ApiService request = retrofit.create(ApiService.class);
Observable<ResponseInfo> observable = request.testGet();// 封裝請求
observable.subscribeOn(Schedulers.io())//網絡請求發生在 子線程
.observeOn(AndroidSchedulers.mainThread())//請求回調發生在 主線程
.subscribe(new Observer<ResponseInfo>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseInfo responseInfo) {
Log.i("gao", "測試 get body = " + responseInfo + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "測試GET= " + responseInfo.content.word_mean.get(0), Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
Log.i("gao", " testGet onFailure " + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, " testGet onFailure ", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {
}
});
}
public void testPost(String string) {
ApiService request = retrofit.create(ApiService.class);
Observable<ResponseInfo> observable = request.testPost(string);// 封裝請求
observable.subscribeOn(Schedulers.io())//網絡請求在子線程
.observeOn(AndroidSchedulers.mainThread())//請求回調在主線程
.subscribe(new Observer<ResponseInfo>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseInfo responseInfo) {
Log.i("gao", "測試 post body = " + responseInfo + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "測試 post body = " + responseInfo, Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
Log.i("gao", "testPost onFailure " + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testPost onFailure ", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {
}
});
}
public void testLoaddown(final String path, String url) {
Retrofit retrofitLoaddown = new Retrofit.Builder()
.baseUrl("http://imtt.dd.qq.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
ApiService request = retrofitLoaddown.create(ApiService.class);
Observable<ResponseBody> observable = request.testDownload(url);//當你填進去的url是完整url的時候,設置的baseurl是無效的
observable.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Observer<ResponseBody>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(ResponseBody responseBody) {
Log.i("gao", "測試 線程名字 = " + Thread.currentThread().getName());
//將Response寫入到從磁盤中,詳見下面分析 注意,這個方法是運行在子線程中的
writeResponseToDisk(path, responseBody);
}
@Override
public void onError(Throwable e) {
Log.i("gao", "testLoaddown 網絡錯誤~ " + " 線程名字 = " + Thread.currentThread().getName());
Toast.makeText(MainActivity.this, "testLoaddown 網絡錯誤~ ", Toast.LENGTH_SHORT).show();
}
@Override
public void onComplete() {
}
});
}
private void writeResponseToDisk(String path, ResponseBody responseBody) {
//從response獲取輸入流以及總大小
writeFileFromIS(new File(path), responseBody.byteStream(), responseBody.contentLength());
}
private static int sBufferSize = 8192;
//將輸入流寫入文件
private void writeFileFromIS(File file, InputStream is, long totalLength) {
//創建文件
if (!file.exists()) {
if (!file.getParentFile().exists())
file.getParentFile().mkdir();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
Log.i("gao", "創建文件錯誤~ " + " 線程名字 = " + Thread.currentThread().getName());
}
}
OutputStream os = null;
long currentLength = 0;
try {
os = new BufferedOutputStream(new FileOutputStream(file));
byte data[] = new byte[sBufferSize];
int len;
while ((len = is.read(data, 0, sBufferSize)) != -1) {
os.write(data, 0, len);
currentLength += len;
//計算當前下載進度
Log.i("gao", "下載 進度 = " + (int) (100 * currentLength / totalLength));
}
//下載完成,並返回保存的文件路徑
Log.i("gao", "下載完成 file.getAbsolutePath() = " + file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
Log.i("gao", "下載失敗");
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
有什麼不明白的可以看我上篇文章,Retrofit的簡單實用(get post 下載文件),裏面詳細的介紹了怎麼使用Rrtrofit。
文章用到的代碼可以去這裏下載 資源。歡迎大家評論,溝通。