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

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