Interfejsy API Androida 4.2

Poziom API: 17

Android 4.2 (JELLY_BEAN_MR1) to aktualizacja wersji Jelly Bean, która oferuje nowe funkcje dla użytkowników i aplikacji dla programistów. W tym dokumencie przedstawiamy najważniejsze i najprzydatniejsze nowe interfejsy API dla programistów.

Jako deweloper aplikacji jak najszybciej pobierz obraz systemu Android 4.2 i platformę SDK z Menedżera pakietu SDK. Jeśli Nie masz urządzenia z Androidem 4.2, na którym chcesz przetestować aplikację, użyj systemu Android 4.2. aby przetestować aplikację przy użyciu emulatora Androida. Następnie skompiluj aplikacje na platformę Android 4.2, aby zacząć korzystać z najnowszych interfejsów API.

Aby lepiej zoptymalizować aplikację na urządzenia z Androidem 4.2, ustaw targetSdkVersion na "17", zainstaluj ją na obrazie systemu Android 4.2, przetestuj ją, a następnie opublikuj aktualizację z tą zmianą.

Możesz używać interfejsów API w Androidzie 4.2, a zarazem obsługiwać starsze wersje, dodając do kodu warunki, które sprawdzają poziom interfejsu API systemu przed wykonaniem interfejsów API nieobsługiwanych przez minSdkVersion. Aby dowiedzieć się więcej o zachowaniu zgodności wstecznej, przeczytaj artykuł Tworzenie interfejsów użytkownika zgodnych wstecznie.

Więcej informacji o tym, jak działają poziomy interfejsu API, znajdziesz w artykule Co to jest poziom interfejsu API?

Ważne zmiany w działaniu

Jeśli aplikacja na Androida została już opublikowana, pamiętaj o tych zmianach, które mogą wpływać na jej działanie:

  • Dostawcy treści nie są już domyślnie eksportowani. Oznacza to, że domyślną wartością atrybutu android:exported jest teraz “false". Jeśli ważne jest, aby inne aplikacje masz dostęp do dostawcy treści, musisz teraz skonfigurować android:exported="true".

    Ta zmiana zostanie wprowadzona tylko wtedy, gdy ustawisz w parametrze android:targetSdkVersion lub android:minSdkVersion wartość 17 lub większą. W innych przypadkach wartość domyślna to nadal “true", nawet na Androidzie 4.2 lub nowszym.

  • W porównaniu z poprzednimi wersjami Androida wyniki dotyczące lokalizacji użytkownika mogą być mniej dokładne, jeśli Twoja aplikacja prosi o uprawnienie ACCESS_COARSE_LOCATION, ale nie prosi o uprawnienie ACCESS_FINE_LOCATION.

    Aby spełnić oczekiwania użytkowników dotyczące prywatności, gdy Twoja aplikacja prosi o dostęp do lokalizacji przybliżonej (a nie dokładnej), system nie podaje oszacowania lokalizacji użytkownika z dokładnością większą niż do bloku ulicznego.

  • Niektóre ustawienia urządzenia zdefiniowane przez użytkownika Settings.System są teraz tylko do odczytu. Jeśli aplikacja próbuje zapisać zmiany w ustawieniach zdefiniowanych w pliku Settings.System, które zostały przeniesione do pliku Settings.Global, operacja zapisu zakończy się bez żadnego komunikatu na Androidzie 4.2 lub nowszym.

    Nawet jeśli wartość android:targetSdkVersionandroid:minSdkVersion jest mniejsza niż 17, aplikacja nie może modyfikować ustawień przeniesionych do Settings.Global, gdy działa na Androidzie 4.2 lub nowszym.

  • Jeśli Twoja aplikacja korzysta z WebView, Android 4.2 zapewnia dodatkową warstwę zabezpieczeń, dzięki której możesz bezpieczniej wiązać JavaScript z kodem Androida. Jeśli ustawisz parametr targetSdkVersion co najmniej 17, musisz teraz dodać adnotację @JavascriptInterface do dowolnej metody które mają być dostępne dla JavaScriptu (metoda musi też być publiczna). Jeśli nie podasz adnotacji, metoda nie będzie dostępna dla strony internetowej w Twoim WebView na Androidzie 4.2 lub nowszym. Jeśli ustawisz parametr targetSdkVersion do 16 lub niższej, adnotacja nie jest wymagana, ale zalecamy zaktualizowanie wersji docelowej i dodać adnotację, aby jeszcze bardziej zwiększyć bezpieczeństwo.

    Dowiedz się więcej o wiązaniu kodu JavaScript z kodem Androida.

Daydream

Daydream to nowy interaktywny tryb wygaszacza ekranu na urządzeniach z Androidem. Aktywuje się automatycznie, gdy urządzenie zostanie umieszczone w dokującej stacji dokującej lub gdy urządzenie jest nieaktywne, a jednocześnie podłączone do ładowarki (zamiast wyłączania ekranu). Daydream wyświetla jeden dream naraz. Może to być czysto wizualny, pasywny wyświetlacz, który znika po dotknięciu, lub może być interaktywny i reagować na pełny zestaw zdarzeń wejściowych. Twoje sny są w procesie działania aplikacji i mają pełny dostęp do zestaw narzędzi interfejsu Androida, w tym widoki, układy i animacje, dzięki czemu są one bardziej elastyczne niż animowane tapety czy widżety aplikacji.

Możesz utworzyć sen dla Daydream, implementując podklasę DreamService. Interfejsy API usługi DreamService są zaprojektowane tak, aby były podobne do komponentów Activity. Aby określić interfejs użytkownika Dream, przekaż identyfikator zasobu układu lub View do setContentView() w dowolnym momencie po okno, np. z onAttachedToWindow() oddzwanianie.

Klasa DreamService udostępnia inne ważne wywołanie zwrotne cyklu życia. w podstawowych interfejsach API Service, takich jak onDreamingStarted(), onDreamingStopped() i onDetachedFromWindow(). Nie możesz rozpocząć DreamService z aplikacji – jest ona uruchamiana automatycznie przez system.

Jeśli Twoje marzenie jest interaktywne, możesz uruchomić z niego aktywność, aby wysłać do niego użytkownika do interfejsu aplikacji, gdzie znajdziesz więcej szczegółów lub większą kontrolę. Możesz użyć finish(), aby zakończyć sen i wyświetlić użytkownikowi nowa aktywność.

Aby udostępnić daydream systemowi, zadeklaruj DreamService za pomocą elementu <service> w pliku manifestu. Potem musisz uwzględnić filtr intencji z działaniem "android.service.dreams.DreamService". Na przykład:

<service android:name=".MyDream" android:exported="true"
    android:icon="@drawable/dream_icon" android:label="@string/dream_label" >
    <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

Inne przydatne metody to DreamService warto wiedzieć:

  • setInteractive(boolean) określa, czy sen otrzymuje zdarzenia wejściowe lub znika natychmiast po wprowadzeniu przez użytkownika danych wejściowych. Jeśli sen jest interaktywny, użytkownik może wyjść z niego, korzystając z przycisków Wstecz lub Strona główna. Możesz też wywołać finish(), aby zatrzymać sen.
  • Jeśli chcesz uzyskać wrażenia pełnego zanurzenia, możesz wywołać setFullscreen(), aby ukryć pasek stanu.
  • Przed uruchomieniem Daydream ekran ściemnia się, aby zasygnalizować użytkownikowi, że zbliża się czas bezczynności. Gdy zadzwonisz pod setScreenBright(true), możesz ustawić standardową jasność wyświetlacza.

Więcej informacji znajdziesz w dokumentacji DreamService.

Wyświetlacze dodatkowe

Android umożliwia teraz wyświetlanie przez aplikację unikalnych treści na dodatkowych ekranach połączonych z urządzeniem użytkownika przewodowo lub przez Wi-Fi. Aby utworzyć unikalną treść na potrzeby dodatkowego wyświetlacza, rozwiń Presentation i zaimplementuj wywołanie zwrotne onCreate(). W onCreate() określ interfejs wyświetlacza dodatkowego, wywołując funkcję setContentView(). Jako rozszerzenie klasy Dialog klasa Presentation określa region, w którym aplikacja może wyświetlać unikalny interfejs użytkownika dodatkowy wyświetlacz.

Aby wykrywać dodatkowe wyświetlacze, na których możesz wyświetlać Presentation, użyj interfejsu API DisplayManager lub MediaRouter. Interfejsy API DisplayManager umożliwiają natomiast wielu wyświetlaczy, które można podłączyć jednocześnie, zwykle lepiej jest używać interfejsu MediaRouter, aby szybko uzyskać dostęp do domyślnego wyświetlacza systemu prezentacje.

Aby uzyskać domyślny sposób wyświetlania prezentacji, wywołaj MediaRouter.getSelectedRoute() i przekaż go ROUTE_TYPE_LIVE_VIDEO Zwraca obiekt MediaRouter.RouteInfo, który opisuje aktualnie wybraną trasę przez system w prezentacjach wideo. Jeśli wartość MediaRouter.RouteInfo nie jest pusta, wywołaj funkcję getPresentationDisplay(), aby uzyskać wartość Display reprezentującą podłączony wyświetlacz.

Następnie możesz wyświetlić prezentację, przekazując obiekt Display do konstruktora klasy Presentation. Prezentacja pojawi się na dodatkowym ekranie.

Aby wykrywać w czasie działania podłączenie nowego wyświetlacza, utwórz instancję MediaRouter.SimpleCallback z zaimplementowaną metodą wywołania zwrotnego onRoutePresentationDisplayChanged(), którą system będzie wywoływał po Podłączono wyświetlacz prezentacji. Następnie zarejestruj MediaRouter.SimpleCallback, przekazując go do usługi MediaRouter.addCallback() wraz z typem trasy ROUTE_TYPE_LIVE_VIDEO. Gdy ktoś do Ciebie zadzwoni onRoutePresentationDisplayChanged(), po prostu zadzwoń pod MediaRouter.getSelectedRoute() zgodnie z opisem powyżej.

Aby jeszcze bardziej zoptymalizować interfejs użytkownika Presentation dla ekranów dodatkowych, możesz zastosować inny motyw, określając atrybut android:presentationTheme w <style>, który został przez Ciebie do aplikacji lub aktywności.

Pamiętaj, że ekrany połączone z urządzeniem użytkownika często mają większy rozmiar i prawdopodobnie inną gęstość pikseli. Charakterystyka ekranu może się różnić, dlatego które są zoptymalizowane pod kątem takich dużych ekranów. Jeśli chcesz poprosić o dodatkowe zasoby z Presentation, wywołaj funkcję getContext().getResources(), aby uzyskać obiekt Resources odpowiadający wyświetlaczowi. Dzięki temu aplikacja udostępnia odpowiednie zasoby, które najlepiej pasują do rozmiaru i gęstości ekranu wyświetlacza dodatkowego.

Więcej informacji i przykłady kodu znajdziesz w dokumentacji klasy Presentation.

Widżety ekranu blokady

Android pozwala teraz użytkownikom dodawać widżety aplikacji do ekranu blokady. Aby widżet aplikacji był dostępny na ekranie blokady, dodaj do pliku XML atrybut android:widgetCategory, który określa AppWidgetProviderInfo. Ten atrybut obsługuje 2 wartości: home_screen i keyguard. Domyślnie atrybut ma wartość home_screen, dzięki czemu użytkownicy mogą dodawać widżet aplikacji do ekranu głównego. Jeśli chcesz, aby widżet aplikacji był też dostępny na ekranie blokady , dodaj wartość keyguard:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:widgetCategory="keyguard|home_screen">
</appwidget-provider>

Musisz też określić początkowy układ widżetu aplikacji na ekranie blokady atrybut android:initialKeyguardLayout. Działa on w taki sam sposób jak android:initialLayout, czyli zapewnia układ, który może się wyświetlać natychmiast, dopóki widżet aplikacji nie zostanie zainicjowany i nie będzie można zaktualizować układu.

Więcej informacji o tworzeniu widżetów aplikacji na ekran blokady, w tym o do zmiany rozmiaru widżetu aplikacji na ekranie blokady znajdziesz w przewodniku Widżety aplikacji.

Wielu użytkowników

Android pozwala teraz na korzystanie z wielu przestrzeni użytkownika na urządzeniach, które można udostępniać, takich jak tablety. Każdy użytkownik na urządzeniu ma własny zestaw kont, aplikacji, ustawień systemowych, plików i innych danych powiązanych z użytkownikiem.

Jako deweloper aplikacji nie musisz nic robić, aby aplikacja działała z wieloma użytkownikami na 1 urządzeniu. Niezależnie od tego, ilu użytkowników korzysta z urządzenia, dane zapisywane przez Twoją aplikację dla danego użytkownika są przechowywane oddzielnie od danych zapisywanych dla innych użytkowników. System śledzi, które dane użytkownika należą do procesu użytkownika, w którym działa Twoja aplikacja, i daje jej dostęp tylko do danych tego użytkownika, a nie do danych innych użytkowników.

Zapisywanie danych w środowisku obejmującym wielu użytkowników

Za każdym razem, gdy aplikacja zapisuje preferencje użytkownika, tworzy bazę danych lub zapisuje plik w w pamięci wewnętrznej lub zewnętrznej, dane te są dostępne tylko wtedy, gdy użytkownik działa jako ten użytkownik.

Aby mieć pewność, że aplikacja działa prawidłowo w środowisku, w którym jest wielu użytkowników, nie używaj wewnętrzny katalog aplikacji lub lokalizację w pamięci zewnętrznej za pomocą zakodowanych na stałe ścieżek, a zamiast tego zawsze używaj odpowiednich interfejsów API:

Niezależnie od tego, którego z tych interfejsów API używasz do zapisywania danych danego użytkownika, nie będą one dostępne, gdy działasz jako inny użytkownik. Z perspektywy aplikacji każdy użytkownik korzysta z zupełnie innego urządzenia.

Identyfikowanie użytkowników w środowisku wieloużytkownika

Jeśli Twoja aplikacja chce identyfikować pojedynczych użytkowników, np. aby zbierać dane analityczne lub tworzyć inne powiązania kont, postępuj zgodnie z zalecanymi metodami identyfikowania niepowtarzalnych instalacji. Tworząc nowy element UUID, gdy aplikacja uruchamia się dla najprawdopodobniej uzyskasz unikalny identyfikator do śledzenia każdego użytkownika, to użytkownicy instalują Twoją aplikację na jednym urządzeniu. Możesz też zapisać token lokalny pobrany z serwera lub użyć identyfikatora rejestracji dostarczonego przez Google Cloud Messaging.

Jeśli aplikacja prosi o jeden z identyfikatorów sprzętowych (np. MAC sieci Wi-Fi), adresu lub numeru SERIAL), zapewnią one tę samą wartość dla każdego z nich ponieważ są one powiązane ze sprzętem, a nie z użytkownikiem. Nie wspominając o innych problemach, które te identyfikatory powodują, jak opisano w poście na blogu Identyfikowanie instalacji aplikacji.

Nowe ustawienia globalne

Ustawienia systemu zostały zaktualizowane, aby obsługiwać wielu użytkowników, a dodatkowo dodano Settings.Global. Ta kolekcja ustawień jest podobna do ustawień Settings.Secure, ponieważ są one tylko do odczytu, ale są stosowane globalnie we wszystkich przestrzeniach użytkownika na urządzeniu.

Kilka dotychczasowych ustawień zostało przeniesionych z poziomu Settings.System lub Settings.Secure. Jeśli Twoja aplikacja wprowadza obecnie zmiany w ustawieniach zdefiniowanych wcześniej w Settings.System (np. AIRPLANE_MODE_ON), należy się spodziewać, że przestanie ona działać na urządzeniu z Androidem 4.2 lub nowszym, jeśli te ustawienia zostały przeniesione do Settings.Global. Możesz nadal czytać ustawienia w sekcji Settings.Global, ale ponieważ ustawienia nie są już uważane za bezpieczne aplikacje, które mogą ulec zmianie, próba zaktualizowania tego błędu zakończy się po cichu, a system doda ostrzeżenie do dziennika systemowego w przypadku uruchomienia aplikacji na urządzeniu z Androidem 4.2 lub nowszym.

Obsługa układu RTL

Android oferuje teraz kilka interfejsów API, które umożliwiają tworzenie interfejsów użytkownika, które płynnie dostosowują orientację układu do obsługi języków z kierunkiem czytania od prawej do lewej (RTL), takich jak arabski czy hebrajski.

Aby zacząć obsługiwać układy RTL w swojej aplikacji, ustaw atrybut android:supportsRtl na element <application> w pliku manifestu i ustaw tę wartość “true". Po włączeniu tej opcji system włączy różne interfejsy API RTL, aby wyświetlać aplikację z układem RTL. Na przykład pasek działań będzie zawierać ikonę i tytuł po prawej stronie, a przyciski działań – po lewej. Wszystkie układy utworzone za pomocą klas View udostępnionych przez framework również będą odwrócone.

Jeśli musisz jeszcze bardziej zoptymalizować wygląd aplikacji w układzie od prawej do lewej, wyróżniamy 2 podstawowe poziomy optymalizacji:

  1. Przekształcanie właściwości układu zorientowanego na lewo i na prawo w właściwości układu zorientowanego na początek i koniec.

    Użyj na przykład android:layout_marginStart zamiast android:layout_marginLeft i android:layout_marginEnd zamiast android:layout_marginRight.

    Klasa RelativeLayout udostępnia też odpowiedni układ atrybuty umożliwiające zastąpienie pozycji lewa/prawa, np. android:layout_alignParentStart na zastąp android:layout_alignParentLeft i android:layout_toStartOf zamiast android:layout_toLeftOf.

  2. Aby zapewnić pełną optymalizację układów od prawej do lewej, możesz przesłać całkowicie osobne pliki układu z kwalifikatorem zasobów ldrtl (ldrtl oznacza układ-direction-right-to-left}). Pliki układu domyślnego możesz na przykład zapisać w Układy zoptymalizowane pod kątem rozmiaru RTL i od prawej do lewej w aplikacji res/layout/ w języku: res/layout-ldrtl/.

    Kwalifikator ldrtl jest przydatny w przypadku zasobów rysowalnych, ponieważ możesz dzięki niemu udostępniać grafiki zorientowane w kierunku zgodnym z kierunkiem czytania.

W ramach platformy dostępne są różne inne interfejsy API obsługujące układy RTL, takie jak klasy View, aby móc zaimplementować prawidłowe zachowania w przypadku i w Configuration, aby wysłać zapytanie dotyczące bieżącego kierunku układu.

Uwaga: jeśli używasz SQlite i masz tabele lub kolumny o nazwach „tylko liczba”, bądź ostrożny: użycie parametru String.format(String, Object...) może spowodować błędy, w których liczby zostaną przekonwertowane na ich odpowiedniki w języku arabskim, jeśli na urządzeniu ustawiono lokalizację arabską. Należy użyć funkcji String.format(Locale,String,Object...), aby zapewnić zachowywany jako ASCII. Możesz też używać atrybutu String.format("%d", int) zamiast String.valueOf(int) za formatowanie liczb.

Zagnieżdżone fragmenty

Fragmenty możesz teraz umieszczać w fragmentach. Jest to przydatne w różnych sytuacjach, w których chcesz umieścić dynamiczne i wielokrotnie użyteczne komponenty UI w komponencie UI, który jest sam w sobie dynamiczny i wielokrotnie użyteczny. Jeśli na przykład używasz ViewPager do tworzy się fragmenty, które przesuwają w lewo i w prawo i zajmują większość miejsca na ekranie, wstaw fragmenty do każdej strony z fragmentami.

Aby zagnieździć fragment, wywołaj po prostu funkcję getChildFragmentManager() Fragment, do którego chcesz dodać fragment. Zwraca to FragmentManager, którego możesz używać tak jak zwykłej aktywności na najwyższym poziomie, aby tworzyć transakcje fragmentów. Oto przykładowy kod, który dodaje fragment z wewnątrz istniejące zajęcia Fragment:

Kotlin

val videoFragment = VideoPlayerFragment()
childFragmentManager.beginTransaction().apply {
    add(R.id.video_fragment, videoFragment)
    commit()
}

Java

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

Z poziomu zagnieżdżonego fragmentu możesz uzyskać odwołanie do fragmentu nadrzędnego, wywołując getParentFragment()

Biblioteka pomocy Androida obsługuje też teraz zagnieżdżone fragmenty, projektowanie fragmentów w systemie Android 1.6 i nowszych.

Uwaga: nie możesz zwiększać zakresu układu, gdy ten układ zawiera element <fragment>. Zagnieżdżone fragmenty są obsługiwane tylko po dodaniu do fragment kodu w wyszukiwarce Google.

Renderscript

Ulepszyliśmy funkcję obliczeń w języku Renderscript o te funkcje:

Instrukcje wewnętrzne skryptu

Możesz używać wbudowanych w Renderscript skryptów, które implementują dla Ciebie typowe operacje, takie jak:

Aby użyć wbudowanego skryptu, wywołaj statyczną metodę create() każdego elementu wewnętrznego aby utworzyć instancję skryptu. Następnie dzwonisz pod dostępny numer set() w ramach poszczególnych skryptów w celu ustawienia niezbędnych danych wejściowych i opcji. Na koniec wywołaj forEach() do wykonania skryptu.

Grupy skryptów

Elementy ScriptGroup umożliwiają łączenie powiązanych ze sobą skryptów renderowania skryptów i wykonywać je za pomocą jednego wywołania.

Aby dodać wszystkie skrypty do grupy, użyj elementu ScriptGroup.Builder , dzwoniąc pod numer addKernel(). Po dodaniu wszystkich skryptów utwórz połączenia między nimi, wywołując funkcję addConnection(). Po dodaniu połączeń wywołaj funkcję create(), aby utworzyć grupę skryptu. Przed wykonaniem grupy skryptów określ dane wejściowe Allocation i początkowy skrypt do uruchomienia z setInput(Script.KernelID, Allocation) i podaj dane wyjściowe. Allocation, w którym zostanie zapisany wynik, a skrypt końcowy na uruchomienia z setOutput(). Na koniec wywołaj funkcję execute(), aby uruchomić grupę skryptów.

Skrypt filtra

Skrypt filtra definiuje ograniczenia dotyczące istniejących interfejsów API Renderscript, które umożliwiają uruchamianie kodu na większej liczbie procesorów (CPU, GPU i DSP). Aby utworzyć pliki Filterscript, utwórz pliki .fs zamiast plików .rs i podaj wartość #pragma rs_fp_relaxed, aby poinformować środowisko wykonawcze Renderscript, że skrypty nie wymagają ścisłej precyzji zmiennoprzecinkowej IEEE 754-2008. Ta dokładność umożliwia wyrównywanie do zera w przypadku denormacji i zaokrąglania do zera. Ponadto skrypty Filterscript nie mogą używać 32-bitowych typów wbudowanych i muszą określać niestandardową funkcję rdzenną za pomocą atrybutu __attribute__((kernel)), ponieważ Filterscript nie obsługuje wskaźników, które są definiowane przez domyślną sygnaturę funkcji root().

Uwaga: chociaż platforma obsługuje filtry, pomoc dla deweloperów będzie dostępna w wersji narzędzi pakietu SDK 21.0.1.

Szczegółowe informacje o wszystkich zmianach interfejsu API w Androidzie 4.2 znajdziesz w raporcie o różnicach w interfejsach API.