Połącz z siecią

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 AAAAA. 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
            }
        });
    }
}

Więcej informacji na ten temat znajdziesz w tych powiązanych przewodnikach: