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 bezpiecznej komunikacji sieciowej
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 ze sprawdzonymi metodami zapewniania 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ą używa protokołu HTTP do wysyłania i odbierania danych. Android
platforma obejmuje
Klient HttpsURLConnection
,
który obsługuje TLS, przesyłanie strumieniowe i pobieranie plików,
konfigurowane limity czasu
IPv6 i pule 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
resolver 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. Dla: np. gdy nastąpiła zdalna zmiana, taka jak aktualizacja punktów końcowych interfejsu API, możesz wdrożyć lokalną pamięć podręczną.
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. Rozmówca z: UserRepository
musi wdrożyć wątki za pomocą współrzędnych lub interfejsu 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ń sieciowych.
Możesz użyć ViewModel
, aby zezwolić
Twoje dane przetrwają 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 poprzedniego elementu UserRepository
, ViewModel
może utworzyć
niezbędne żądania sieciowe i dostarczać wyniki we fragmencie lub działaniu
przy użyciu 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