連線到網路

如要在應用程式中執行網路作業,資訊清單必須包含下列權限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

安全網路通訊的最佳做法

將網路功能加入應用程式前,您必須確保應用程式內的資料和資訊在透過網路傳輸時安全無虞。如要這麼做的話,請按照下列網路安全性最佳做法操作:

  • 請盡量減少透過網路傳輸機密或個人使用者資料
  • 應用程式透過 SSL,傳送到所有網絡。
  • 建議您建立網路安全性設定,讓應用程式信任自訂憑證授權單位 (CA),或限制可信任通訊的 CA 系統組合。

如要進一步瞭解如何套用安全網路的原則,請參閱「網路安全性提示」

選擇 HTTP 用戶端

大多數具備網路連線的應用程式會使用 HTTP 傳送及接收資料。Android 平台包括 HttpsURLConnection 用戶端,其支援傳輸層安全標準 (TLS)、串流上傳和下載、可設定逾時、IPv6 和連線集區。本主題使用 Retrofit HTTP 用戶端程式庫,讓您透過宣告建立 HTTP 用戶端。Retrofit 也支援自動對要求體的序列化程序,以及回應體的去序列化功能。

解決 DNS 查詢

搭載 Android 10 (API 級別 29) 或以上版本的裝置,有原生支援確切文字查詢和 DNS-over-TLS 模式,做為專門用於處理 DNS 查詢。DnsResolver API 提供一般的非同步解析,可讓您查詢 SRVNAPTR 和其他記錄類型。請注意,剖析回應會留在應用程式中執行。

在搭載 Android 9 (API 級別 28) 或以下版本的裝置上,平台 DNS 解析器僅支援 AAAAA 記錄。這可讓您查詢與名稱相關聯的 IP 位址,但不支援任何其他記錄類型。

如需以 NDK 為基礎的應用程式,請參閱 android_res_nsend 的說明。

使用存放區封裝網路作業

如要簡化執行網路作業的流程,並減少應用程式中各部分的程式碼重複,您可以使用存放區設計模板。存放區是一種資料處理作業的類別,也是針對某些特定資料或資源提供簡潔的 API 抽象層。

您可以使用 Retrofit 宣告介面,指定網路作業的 HTTP 方法、網址、引數和回應類型,如以下範例所示:

Kotlin

interface UserService {
    @GET("/users/{id}")
    suspend fun getUser(@Path("id") id: String): User
}

Java

public interface UserService {
    @GET("/user/{id}")
    Call<User> getUserById(@Path("id") String id);
}

在存放區類別中,函式可以封裝網路作業並公開結果。這個封裝可確保呼叫存放區的元件,並不需要知道資料的儲存方式。日後凡是將資料儲存方式的變更,都會一併儲存在存放區類別。

Kotlin

class UserRepository constructor(
    private val userService: UserService
) {
    suspend fun getUserById(id: String): User {
        return userService.getUser(id)
    }
}

Java

class UserRepository {
    private UserService userService;

    public UserRepository(
            UserService userService
    ) {
        this.userService = userService;
    }

    public Call<User> getUserById(String id) {
        return userService.getUser(id);
    }
}

為了避免建立沒有回應的 UI,請勿在主執行緒中執行網路作業。根據預設,Android 會要求您在主 UI 執行緒以外的執行緒上執行網路作業;否則,系統會擲回 NetworkOnMainThreadException。在上述程式碼範例所示的 UserRepository 類別中,系統實際上並未觸發網路作業。UserRepository 的呼叫者必須使用相關呼叫或 enqueue() 函式來實作執行緒。

在設定變更後仍然有效

發生設定變更 (例如畫面旋轉) 時,系統會刪除您的片段或活動,再重新建立工作。任何未儲存的資料片段或活動(只會保留少量資料)遺失,您可能需要再次發出網路要求。

您可以使用 ViewModel,確保資料在設定變更後仍然有效。ViewModel 元件是用生命週期的管理方式在設計儲存和管理 UI 相關資料。使用上述建立的 UserRepositoryViewModel 即可發出必要的網路要求,並使用 LiveData 將結果提供給片段或活動:

Kotlin

class MainViewModel constructor(
    savedStateHandle: SavedStateHandle,
    userRepository: UserRepository
) : ViewModel() {
    private val userId: String = savedStateHandle["uid"] ?:
        throw IllegalArgumentException("Missing user ID")

    private val _user = MutableLiveData<User>()
    val user = _user as LiveData<User>

    init {
        viewModelScope.launch {
            try {
                // Calling the repository is safe as it will move execution off
                // the main thread
                val user = userRepository.getUserById(userId)
                _user.value = user
            } catch (error: Exception) {
                // show error message to user
            }

        }
    }
}

Java

class MainViewModel extends ViewModel {

    private final MutableLiveData<User> _user = new MutableLiveData<>();
    LiveData<User> user = (LiveData<User>) _user;

    public MainViewModel(
            SavedStateHandle savedStateHandle,
            UserRepository userRepository
    ) {
        String userId = savedStateHandle.get("uid");
        Call<User> userCall = userRepository.getUserById(userId);
        userCall.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    _user.setValue(response.body());
                }
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                // show error message to user
            }
        });
    }
}

如要進一步瞭解這個主題,請參閱下列相關指南: