介紹到了最後一篇了,最後就來介紹Retrofit和RxJava,那我們就開始吧 (¦3[▓▓]
當 App 需要與後端伺服器進行資料交換時,我們需要一個穩定的網路請求方案。Retrofit和RxJava 的組合,讓處理複雜的網路操作和執行緒切換變得輕鬆簡單
Retrofit透過一個Adapter,可以直接將API的回應轉換成RxJava 的Observable 或Single物件。這讓我們可以利用RxJava的鏈式操作符來處理、轉換和組合網路回應,並用其內建的排程器在背景執行緒執行網路請求,然後在主執行緒更新 UI
Retrofit Instance:透過Retrofit.Builder 建立的單例物件,設定了 API 的基底 URL、資料轉換器和轉接器
API Interface:Java介面,使用 Retrofit 的註解 (@GET, @POST, @Path 等) 來定義所有的 API 端點
資料模型:用來對應 API 回應 JSON 結構的 Java 物件
Gson Converter:Retrofit的轉換器,負責自動將JSON 字串與 Java 物件進行序列化和反序列化
RxJava Adapter:Retrofit的轉接器,讓 API 介面中的方法可以回傳 RxJava 的 Observable 或 Single 型別
RxJava Schedulers:RxJava 的執行緒排程器,Schedulers.io() 用於執行 I/O 密集型任務(如網路請求),AndroidSchedulers.mainThread() 用於在 Android 的主執行緒執行任務
Disposable / CompositeDisposable:RxJava 中的訂閱控制器。每次訂閱都會產生一個 Disposable 物件,我們需要用 CompositeDisposable 容器來管理它們,並在Activity/Fragment銷毀時取消所有訂閱,防止記憶體洩漏
我們用免費的線上測試API JSONPlaceholder,連結點進去後往下滑,我們用黃色框的連結來作範例

先在build.gradle檔案中加入依賴
dependencies {
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:3.0.0'
// Gson Converter
implementation 'com.squareup.retrofit2:converter-gson:3.0.0'
// RxJava 3 Adapter
implementation 'com.squareup.retrofit2:adapter-rxjava3:3.0.0'
// RxJava 3
implementation 'io.reactivex.rxjava3:rxjava:3.1.12'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
}
在AndroidManifest.xml 中宣告網路權限
<uses-permission android:name="android.permission.INTERNET" />
根據 API 回應的 JSON 格式建立 Post.java,下面是連結點進去後的格式,然後就照上面格式寫

Post.java
import com.google.gson.annotations.SerializedName;
public class Post {
@SerializedName("id")
private int id;
@SerializedName("userId")
private int userId;
@SerializedName("title")
private String title;
@SerializedName("body")
private String body;
// Getters and Setters...
public int getId() { return id; }
public String getTitle() { return title; }
public String getBody() { return body; }
}
ApiService.java:
import io.reactivex.rxjava3.core.Single;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface ApiService {
//Single<T>適用於那種只會發射一次資料或一個錯誤的場景
@GET("posts/{id}")//這邊就是@GET https://jsonplaceholder.typicode.com/posts/1後面的posts/1,前面的BASE_URL會另外寫
Single<Post> getPost(@Path("id") int postId);
}
建立一個單例的 Retrofit Client 來提供ApiService的實例。
RetrofitClient.java:
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
private static final String BASE_URL = "https://jsonplaceholder.typicode.com/";
private static Retrofit instance;
public static Retrofit getInstance() {
if (instance == null) {
instance = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()) //加入Gson轉換器
.addCallAdapterFactory(RxJava3CallAdapterFactory.create()) //加入RxJava轉接器
.build();
}
return instance;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:id="@+id/result_main_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
MainActivity.java:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.observers.DisposableSingleObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;
import retrofit2.Retrofit;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";//這行方便偵錯用
private TextView resultTextView;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();//建立一個CompositeDisposable來管理所有的訂閱
private ApiService apiService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultTextView= findViewById(R.id.result_main_tv);
//取得ApiService 實例
apiService = RetrofitClient.getInstance().create(ApiService.class);
fetchPost();
}
private void fetchPost() {
resultTextView.setText("載入中...");
//發起請求並串接RxJava 操作符
compositeDisposable.add(apiService.getPost(1)
.subscribeOn(Schedulers.io()) //指定網路請求在I/O 執行緒中執行
.observeOn(AndroidSchedulers.mainThread()) //指定觀察者在主執行緒中執行
.subscribeWith(new DisposableSingleObserver<Post>() { //建立一個觀察者
@Override
public void onSuccess(Post post) {
//當請求成功時呼叫
String content = "";
content += "ID: " + post.getId() + "\n";
content += "Title: " + post.getTitle() + "\n";
content += "Body: " + post.getBody() + "\n";
resultTextView.setText(content);
}
@Override
public void onError(Throwable e) {
//當請求發生錯誤時呼叫
resultTextView.setText("錯誤: " + e.getMessage());
Log.e(TAG, "onError: ", e);
}
})
);
}
@Override
protected void onDestroy() {
super.onDestroy();
//在Activity銷毀時,取消所有訂閱
compositeDisposable.clear();
}
}
subscribeOn(Schedulers.io())將網路請求切換到背景執行緒,並用 observeOn(AndroidSchedulers.mainThread())將結果切換回主執行緒來更新 UICompositeDisposable 來管理所有訂閱,並在 onDestroy() 中呼叫 clear() 或 dispose()
onError回呼是處理所有類型錯誤(網路中斷、伺服器錯誤、JSON 解析失敗等)的集中地,要做好完整的錯誤處理恭喜我們剩下最後一天,明天會來為這個30天鐵人賽做個結尾,最後一天見了各位( ՞ټ՞)
