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:exportedjest 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:targetSdkVersionlubandroid:minSdkVersionwartość 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 uprawnienieACCESS_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.Systemsą teraz tylko do odczytu. Jeśli aplikacja próbuje zapisać zmiany w ustawieniach zdefiniowanych w plikuSettings.System, które zostały przeniesione do plikuSettings.Global, operacja zapisu zakończy się bez żadnego komunikatu na Androidzie 4.2 lub nowszym.Nawet jeśli wartość
android:targetSdkVersioniandroid:minSdkVersionjest mniejsza niż 17, aplikacja nie może modyfikować ustawień przeniesionych doSettings.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 parametrtargetSdkVersionco najmniej 17, musisz teraz dodać adnotację@JavascriptInterfacedo 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 TwoimWebViewna Androidzie 4.2 lub nowszym. Jeśli ustawisz parametrtargetSdkVersiondo 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:
- Aby uzyskać dostęp do pamięci wewnętrznej, użyj aplikacji
getFilesDir(),getCacheDir()lubopenFileOutput(). - Aby uzyskać dostęp do pamięci zewnętrznej, użyj
getExternalFilesDir()lubgetExternalStoragePublicDirectory().
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:
- 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_marginStartzamiastandroid:layout_marginLeftiandroid:layout_marginEndzamiastandroid:layout_marginRight.Klasa
RelativeLayoutudostępnia też odpowiedni układ atrybuty umożliwiające zastąpienie pozycji lewa/prawa, np.android:layout_alignParentStartna zastąpandroid:layout_alignParentLeftiandroid:layout_toStartOfzamiastandroid:layout_toLeftOf. - 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(ldrtloznacza 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 aplikacjires/layout/w języku:res/layout-ldrtl/.Kwalifikator
ldrtljest 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:
BlendsBlurColor matrix3x3 convolve5x5 convolvePer-channel lookup tableConverting an Android YUV buffer to RGB
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 numerset()w ramach poszczególnych skryptów w celu ustawienia niezbędnych danych wejściowych i opcji. Na koniec wywołajforEach()do wykonania skryptu.- Grupy skryptów
-
Elementy
ScriptGroupumoż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 numeraddKernel(). 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ścioweAllocationi początkowy skrypt do uruchomienia zsetInput(Script.KernelID, Allocation)i podaj dane wyjściowe.Allocation, w którym zostanie zapisany wynik, a skrypt końcowy na uruchomienia zsetOutput(). 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
.fszamiast plików.rsi 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ę funkcjiroot().
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.