如要在應用程式中執行網路作業,資訊清單必須包含下列權限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
安全網路通訊的最佳做法
將網路功能加入應用程式前,您需要確保應用程式內的資料和資訊在透過網路傳輸時安全無虞。如要這麼做的話,請按照下列網路安全性最佳做法操作:
如要進一步瞭解如何套用安全網路的原則,請參閱網路安全性提示。
選擇 HTTP 用戶端
大多數具備網路連線的應用程式會使用 HTTP 傳送及接收資料。Android 平台包括 HttpsURLConnection
用戶端,其支援傳輸層安全標準 (TLS)、串流上傳和下載、可設定逾時、IPv6 和連線集區。
此外,某些第三方程式庫也提供更高階的網路作業 API。這些 API 可支援各種便利功能,例如將要求主體序列化,以及將回應主體反序列化。
- Retrofit:這個類型安全的 HTTP 用戶端適用於 Square 的 JVM,以 OkHttp 為建構基礎。Retrofit 可讓您以宣告方式建立用戶端介面,同時支援多個序列化程式庫。
- Ktor:這個 JetBrains 的 HTTP 用戶端全為 Kotlin 建構而成,採用協同程式提供的技術。Ktor 支援各種引擎、序列化程式和平台。
解析 DNS 查詢
搭載 Android 10 (API 級別 29) 以上版本的裝置內建支援功能,可同時透過明文查詢和「透過 TLS 執行 DNS」模式專門處理 DNS 查詢。DnsResolver
API 提供一般的非同步解析,可讓您查詢 SRV
、NAPTR
和其他記錄類型。請注意,剖析回應會留在應用程式中執行。
在搭載 Android 9 (API 級別 28) 或以下版本的裝置上,平台 DNS 解析器僅支援 A
和 AAAA
記錄。這可讓您查詢與名稱相關聯的 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); }
在存放區類別中,函式可以封裝網路作業並公開結果。這個封裝可確保呼叫存放區的元件,並不需要知道資料的儲存方式。日後若資料儲存方式有所變更,也都只會侷限在存放區類別之中。舉例來說,您可能會想進行遠端變更 (例如更新 API 端點),或是想要導入本機快取,這些都屬於上述情況。
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
的呼叫者必須使用協同程式或 enqueue()
函式來實作執行緒。詳情請參閱「從網際網路取得資料」程式碼研究室,瞭解如何使用 Kotlin 協同程式實作執行緒。
在設定變更後仍然有效
發生設定變更 (例如畫面旋轉) 時,系統會刪除您的片段或活動,再重新建立工作。由於片段活動的實例狀態中只能儲存少量資料,因此任何未儲存的資料都會遺失。如果發生這種情況,您可能需要再次發出網路要求。
您可以使用 ViewModel
,確保資料在設定變更後仍然有效。ViewModel
元件的設計可讓您以注重生命週期的方式儲存及管理 UI 相關資料。如果您使用上述 UserRepository
,ViewModel
即可發出必要的網路要求,並使用 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 moves 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 } }); } }
閱讀相關指南
如要進一步瞭解這個主題,請參閱下列相關指南: