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
lubandroid: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 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.System
są 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:targetSdkVersion
iandroid:minSdkVersion
jest 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 parametrtargetSdkVersion
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 TwoimWebView
na Androidzie 4.2 lub nowszym. Jeśli ustawisz parametrtargetSdkVersion
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:
- 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_marginStart
zamiastandroid:layout_marginLeft
iandroid:layout_marginEnd
zamiastandroid: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ąpandroid:layout_alignParentLeft
iandroid:layout_toStartOf
zamiastandroid: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
(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 aplikacjires/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:
Blends
Blur
Color matrix
3x3 convolve
5x5 convolve
Per-channel lookup table
Converting 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
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 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ścioweAllocation
i 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
.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ę 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.