Aby można było wykonywać operacje sieciowe w aplikacji, plik manifestu musi zawierać te uprawnienia:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Sprawdzone metody dotyczące bezpiecznej komunikacji w sieci
Zanim dodasz do aplikacji funkcje sieciowe, sprawdź, czy: dane i informacje w aplikacji pozostają bezpieczne, gdy przesyłasz przez Aby to zrobić, postępuj zgodnie z tymi sprawdzonymi metodami dotyczącymi bezpieczeństwa sieci:
- Zminimalizuj liczbę kontrowersyjnych lub osobistych użytkowników danych, które przesyłasz za pomocą
- Wysyłaj cały ruch w sieci ze swojej aplikacji przez SSL
- Rozważ utworzenie zabezpieczeń sieci , która umożliwia aplikacji ufać niestandardowym urzędom certyfikacji (CA) lub ograniczać zestaw systemowych urzędów certyfikacji w bezpiecznej komunikacji.
Więcej informacji o stosowaniu zasad bezpiecznego połączenia znajdziesz w wskazówkami na temat bezpieczeństwa sieci.
Wybierz klienta HTTP
Większość aplikacji połączonych z siecią do wysyłania i odbierania danych używa protokołu HTTP. Platforma Androida zawiera klienta HttpsURLConnection
, który obsługuje TLS, przesyłanie i pobieranie strumieniowe, konfigurowalne limity czasu, IPv6 oraz zespół połączeń.
Biblioteki zewnętrzne, które oferują interfejsy API wyższego poziomu na potrzeby operacji sieciowych, to: dostępny jest też algorytm. Obejmują one różne funkcje zwiększające wygodę, takie jak serializacji treści żądań i deserializacji ciał odpowiedzi.
- Retrofit: bezpieczny typ HTTP, dla JVM firmy Square, opartym na technologii OkHttp. Retrofit daje Ci deklaratywne tworzenie interfejsu klienta i obsługuje z bibliotekami serializacji.
- Ktor: klient HTTP od JetBrains, wyłącznie z myślą o Kotlin i o współdziałaniu. Ktor obsługuje różne silniki, serializatory i platformy.
Rozwiązywanie zapytań DNS
Urządzenia z Androidem 10 (poziom interfejsu API 29) lub nowszym mają wbudowaną obsługę
specjalistyczne wyszukiwania DNS z użyciem nieszyfrowanego tekstu i trybu DNS-over-TLS.
Interfejs API DnsResolver
udostępnia ogólne,
rozdzielczość asynchroniczna, która umożliwia wyszukiwanie SRV
, NAPTR
i innych
różnych typów rekordów. Analiza odpowiedzi jest pozostawiana do wykonania aplikacji.
Na urządzeniach z Androidem 9 (poziom interfejsu API 28) lub starszym platformowy serwer DNS obsługuje tylko rekordy A
i AAAA
. Umożliwia to wyszukanie adresu IP
adresów powiązanych z nazwą, ale nie obsługuje żadnych innych typów rekordów.
W przypadku aplikacji opartych na NDK zobacz
android_res_nsend
Enkapuluj operacje sieciowe za pomocą repozytorium
Aby uprościć proces wykonywania operacji sieciowych i ograniczyć kod duplikacji w różnych częściach aplikacji, można wykorzystać projekt repozytorium wzorcem. Repozytorium to klasa, która obsługuje operacje na danych i udostępnia czystość abstrakcji interfejsu API w konkretnych danych lub zasobach.
Możesz użyć Retrofit, by zadeklarować interfejs, który określa metodę HTTP, Adres URL, argumenty i typ odpowiedzi dla operacji sieciowych, jak w tym przykładzie przykład:
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); }
W ramach klasy repozytorium funkcje mogą zawierać operacje sieciowe oraz i ujawnić ich wyniki. Dzięki temu komponenty wywołujące nie muszą wiedzieć, jak dane są przechowywane. Wszelkie przyszłe zmiany w sposób przechowywania danych jest odizolowany także od klasy repozytorium. Możesz na przykład wprowadzić zmianę zdalna, np. zaktualizować punkty końcowe interfejsu API, lub wdrożyć lokalne buforowanie.
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); } }
Aby uniknąć utworzenia interfejsu, który nie odpowiada, nie wykonuj operacji sieciowych na
w wątku głównym. Domyślnie Android wymaga wykonywania operacji sieciowych na
innym niż główny wątek UI. Jeśli próbujesz wykonać operacje sieciowe
w wątku głównym,
NetworkOnMainThreadException
rzucona.
W poprzednim przykładzie kodu para klucz-wartość
które nie są wywoływane przez funkcje sieciowe. Wywołujący UserRepository
musi zaimplementować wątki za pomocą coroutines lub funkcji enqueue()
. Więcej informacji znajdziesz w ćwiczeniu w Codelabs Pobieranie danych z
internet,
który pokazuje, jak wdrożyć łączenie wątków za pomocą współrzędnych Kotlina.
Przetrwaj zmiany konfiguracji
Gdy nastąpi zmiana konfiguracji, np. obrót ekranu, jest zniszczona i odtwarzana. Wszystkie dane nie są zapisane w instancji. dla aktywności dotyczącej fragmentów, która może zawierać tylko niewielkie ilości danych, przepada. W takim przypadku może być konieczne ponowne wysłanie żądań do sieci.
Możesz użyć ViewModel
, aby dane przetrwały zmiany konfiguracji. Komponent ViewModel
to
zaprojektowany do przechowywania danych związanych z interfejsem użytkownika i zarządzania nimi w sposób odzwierciedlający cykl życia
sposób. Korzystając z poprzedniej funkcji UserRepository
, element ViewModel
może wysyłać niezbędne żądania sieciowe i przekazywać wyniki do fragmentu lub czynności za pomocą funkcji 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 } }); } }
Przeczytaj powiązane przewodniki
Więcej informacji na ten temat znajdziesz w tych powiązanych przewodnikach:
- Zmniejszanie obciążenia baterii sieci: omówienie
- Zminimalizuj wpływ regularnych aktualizacji
- Treści internetowe
- Podstawy aplikacji
- Przewodnik po architekturze aplikacji