Livello API: 17
Android 4.2 (JELLY_BEAN_MR1
)
è un aggiornamento della release Jelly Bean che offre nuove funzionalità per gli utenti e gli sviluppatori di app. Questo documento fornisce un'introduzione alle nuove API più importanti e utili per gli sviluppatori.
In qualità di sviluppatore di app, devi scaricare l'immagine di sistema e la piattaforma SDK di Android 4.2 il prima possibile da SDK Manager. Se non hai un dispositivo con Android 4.2 su cui testare la tua app, utilizza l'immagine di sistema Android 4.2 per testarla nell'emulatore Android. Quindi crea le tue app sulla base della piattaforma Android 4.2 per iniziare a utilizzare le API più recenti.
Per ottimizzare meglio la tua app per i dispositivi con Android 4.2,
devi impostare targetSdkVersion
su
"17"
, installalo su un'immagine di sistema Android 4.2,
testarlo, quindi pubblicare un aggiornamento con questa modifica.
Puoi
utilizzare le API in Android 4.2 e supportare contemporaneamente le versioni precedenti aggiungendo
condizioni al codice che controllano il livello dell'API di sistema prima di eseguire
le API non supportate dal tuo minSdkVersion
.
Per scoprire di più su come mantenere la compatibilità con le versioni precedenti, leggi l'articolo Creare UI compatibili con le versioni precedenti.
Per saperne di più sul funzionamento dei livelli API, consulta Che cos'è il livello API?
Modifiche importanti al comportamento
Se hai già pubblicato un'app per Android, tieni presente quanto segue modifiche che potrebbero influire sul comportamento della tua app:
- I fornitori di contenuti non vengono più esportati per impostazione predefinita. In altre parole, il valore predefinito per l'attributo
android:exported
è ora“false"
. Se è importante che altre app possano accedere al tuo fornitore di contenuti, ora devi impostare esplicitamenteandroid:exported="true"
.Questa modifica viene applicata solo se imposti
android:targetSdkVersion
oandroid:minSdkVersion
su un valore pari o superiore a 17. In caso contrario, il valore predefinito è sempre“true"
anche con Android 4.2 e versioni successive. - Rispetto alle versioni precedenti di Android, i risultati relativi alla posizione dell'utente potrebbero essere meno precisi
se la tua app richiede l'autorizzazione
ACCESS_COARSE_LOCATION
, ma non richiede l'autorizzazioneACCESS_FINE_LOCATION
.Per soddisfare le aspettative degli utenti in materia di privacy quando la tua app richiede l'autorizzazione per la posizione approssimativa (e non per la posizione esatta), il sistema non fornirà una stima della posizione dell'utente più precisa di un isolato.
- Alcune impostazioni del dispositivo definite da
Settings.System
sono ora di sola lettura. Se la tua app tenta di scrivere modifiche alle impostazioni definite inSettings.System
che sono state spostate inSettings.Global
, l'operazione di scrittura non riuscirà in modo invisibile su Android 4.2 e versioni successive.Anche se il valore di
android:targetSdkVersion
eandroid:minSdkVersion
è inferiore a 17, la tua app non è in grado di modificare le impostazioni spostate inSettings.Global
quando viene eseguita su Android 4.2 e versioni successive. - Se la tua app utilizza
WebView
, Android 4.2 aggiunge un ulteriore livello di in modo da poter associare più sicuro JavaScript al tuo Codice Android. Se impostitargetSdkVersion
su 17 o versioni successive, ora devi aggiungere l'annotazione@JavascriptInterface
a qualsiasi metodo che vuoi rendere disponibile per il tuo codice JavaScript (il metodo deve essere anche pubblico). Se non fornisci l'annotazione, il metodo non è accessibile da una pagina web nel tuoWebView
quando viene eseguito su Android 4.2 o versioni successive. Se imposti il parametrotargetSdkVersion
alla 16 o a una versione precedente, l'annotazione non è obbligatoria, ma ti consigliamo di aggiornare la versione di destinazione e aggiungi l'annotazione per maggiore sicurezza.Scopri di più sull'associazione da codice JavaScript a codice Android.
Daydream
Daydream è una nuova modalità di salvaschermo interattivo per i dispositivi Android. Si attiva automaticamente quando il dispositivo viene inserito nella base o quando viene lasciato inattivo mentre è collegato a un caricabatterie (anziché spegnere lo schermo). Daydream mostra un sogno alla volta, che può essere una visualizzazione passiva puramente visiva che si chiude al tocco oppure interattiva e adattabile all'intera suite di eventi di input. I tuoi sogni vengono inseriti nel processo della tua app e hanno accesso completo il toolkit per la UI di Android, che comprende visualizzazioni, layout e animazioni, in modo da essere più flessibili potente degli sfondi animati o dei widget di app.
Puoi creare un sogno per Daydream implementando una sottoclasse DreamService
. Le API DreamService
sono progettate per essere simili a quelle di Activity
. Per specificare l'UI per
Inoltre, passa un ID risorsa di layout o View
a setContentView()
in qualsiasi momento, dopo aver
una finestra, ad esempio da onAttachedToWindow()
di Google.
La classe DreamService
fornisce altri metodi di callback importanti del ciclo di vita oltre alle API Service
di base, come onDreamingStarted()
, onDreamingStopped()
e onDetachedFromWindow()
.
Non puoi avviare un DreamService
dalla tua app, perché viene avviato automaticamente dal sistema.
Se il tuo sogno è interattivo, puoi avviare un'attività dal sogno per indirizzare l'utente all'interfaccia utente completa della tua app per maggiori dettagli o controlli. Puoi usare finish()
per terminare il tuo sogno in modo che l'utente possa vedere
nuova attività.
Per rendere il tuo daydream disponibile al sistema, dichiara DreamService
con un elemento <service>
nel file manifest. Devi quindi includere un filtro per intent con l'azione "android.service.dreams.DreamService"
. Ad esempio:
<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>
Esistono altri metodi utili in DreamService
tieni presente:
setInteractive(boolean)
controlla se il sogno riceve eventi di input o esce immediatamente al successivo input dell'utente. Se il sogno è collaborativo, l'utente può utilizzare i pulsanti Indietro o Home per uscirne oppure puoi chiamarefinish()
per interromperlo.- Se vuoi un display completamente immersivo, puoi chiamare
setFullscreen()
per nascondere la barra di stato. - Prima dell'avvio di Daydream, la luminosità del display si attenua per segnalare all'utente che il timeout per inattività
si sta avvicinando. Se chiami
setScreenBright(true)
puoi invece impostare il display alla luminosità abituale.
Per saperne di più, consulta la documentazione di DreamService
.
Display secondari
Ora Android consente alla tua app di mostrare contenuti unici su schermi aggiuntivi collegati al dispositivo dell'utente tramite una connessione cablata o Wi-Fi.
Per creare contenuti unici per una visualizzazione secondaria, espandi la classe Presentation
e implementa il callback onCreate()
. Entro
onCreate()
, specifica la tua UI per il display secondario
chiamando il numero setContentView()
.
Come estensione della classe Dialog
, la classe Presentation
fornisce la regione in cui la tua app può visualizzare un'interfaccia utente univoca sul display secondario.
Per rilevare display secondari dove puoi mostrare il tuo Presentation
:
usa DisplayManager
o MediaRouter
su quelle di livello inferiore. Sebbene le API DisplayManager
ti consentano di enumerare più display che possono essere collegati contemporaneamente, in genere dovresti utilizzare MediaRouter
per accedere rapidamente al display predefinito del sistema per le presentazioni.
Per ottenere la visualizzazione predefinita per la tua presentazione, chiama MediaRouter.getSelectedRoute()
e superala
ROUTE_TYPE_LIVE_VIDEO
. Restituisce un oggetto MediaRouter.RouteInfo
che descrive il percorso attualmente selezionato dal sistema per le presentazioni video. Se MediaRouter.RouteInfo
non è null, richiama
getPresentationDisplay()
per visualizzare il Display
che rappresenta il display connesso.
Puoi quindi visualizzare la presentazione passando l'oggetto Display
a un costruttore per la classe Presentation
. La presentazione verrà visualizzata sul display secondario.
Per rilevare in fase di runtime quando è stato collegato un nuovo display, crea un'istanza di MediaRouter.SimpleCallback
in cui implementi il metodo di callback onRoutePresentationDisplayChanged()
, che verrà chiamato dal sistema quando viene collegato un nuovo display per le presentazioni. Poi registra il valore MediaRouter.SimpleCallback
passandolo a MediaRouter.addCallback()
insieme al tipo di percorso ROUTE_TYPE_LIVE_VIDEO
. Quando ricevi una chiamata al numero onRoutePresentationDisplayChanged()
, chiama semplicemente MediaRouter.getSelectedRoute()
come indicato sopra.
Per ottimizzare ulteriormente l'interfaccia utente in Presentation
per le schermate secondarie, puoi applicare un tema diverso specificando l'attributo android:presentationTheme
in <style>
che hai applicato alla tua applicazione o attività.
Tieni presente che gli schermi collegati al dispositivo dell'utente spesso hanno schermi di dimensioni maggiori e
potrebbe avere una densità dello schermo diversa. Poiché le caratteristiche dello schermo possono variare, devi fornire risorse ottimizzate specificamente per questi display più grandi. Se hai bisogno di richiedere risorse aggiuntive dal tuo Presentation
, chiama getContext()
.getResources()
per ottenere l'oggetto Resources
corrispondente al display. Ciò fornisce
le risorse della tua app più adatte
dimensioni e densità dello schermo secondario.
Per ulteriori informazioni e alcuni esempi di codice, consulta la Presentation
documentazione del corso.
Widget schermata di blocco
Android ora consente agli utenti di aggiungere widget delle app alla schermata di blocco. Per rendere disponibile il widget dell'app per l'utilizzo nella schermata di blocco, aggiungi al file XML l'attributo android:widgetCategory
che specifica AppWidgetProviderInfo
. Questo attributo supporta due valori: home_screen
e keyguard
. Per impostazione predefinita, l'attributo è impostato su home_screen
, quindi gli utenti possono aggiungere il tuo
widget dell'app alla schermata Home. Se vuoi che il widget dell'app sia disponibile anche sulla serratura
schermata, aggiungi il valore keyguard
:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
Devi anche specificare un layout iniziale per il widget dell'app quando è nella schermata di blocco con
l'attributo android:initialKeyguardLayout
. Funziona allo stesso modo di android:initialLayout
, in quanto fornisce
un layout che possa essere visualizzato immediatamente fino a quando il widget dell'app non viene inizializzato e può aggiornare il
layout.
Per ulteriori informazioni sulla creazione di widget per app per la schermata di blocco, inclusa la dimensione corretta del widget dell'app quando è attivo nella schermata di blocco, consulta la guida Widget per app.
Più utenti
Android ora consente più spazi utente su dispositivi condivisibili come i tablet. Ogni utente su un dispositivo ha il proprio insieme di account, app, impostazioni di sistema, file e altri dati associati all'utente.
In qualità di sviluppatore di app, non devi fare nulla per far funzionare la tua app in modo adeguato con più utenti su un unico dispositivo. Indipendentemente dal numero di utenti che possono esistere dispositivo, i dati salvati dall'app per un determinato utente vengono mantenuti separati da quelli salvati dall'app per altri utenti. Il sistema tiene traccia di quali dati utente appartengono al processo utente in cui che l'app sia in esecuzione, che fornisce l'accesso all'app solo ai dati di quell'utente e non consente l'accesso ai dati di altri utenti.
Salvare i dati in un ambiente multiutente
Ogni volta che l'app salva le preferenze dell'utente, crea un database o scrive un file di archiviazione interna o esterna, i dati sono accessibili solo mentre l'utente è in esecuzione.
Per assicurarti che la tua app si comporti correttamente in un ambiente multiutente, non fare riferimento alla directory dell'app interna o alla posizione di archiviazione esterna utilizzando percorsi hardcoded, ma utilizza sempre le API appropriate:
- Per accedere alla memoria interna, usa
getFilesDir()
,getCacheDir()
oopenFileOutput()
. - Per accedere alla memoria esterna, usa
getExternalFilesDir()
ogetExternalStoragePublicDirectory()
.
Indipendentemente da quale di queste API utilizzi per salvare i dati di un determinato utente, i dati non saranno accessibili se esegui l'operazione come utente diverso. Dal punto di vista dell'app, ogni utente esegue l'app su un dispositivo completamente separato.
Identificare gli utenti in un ambiente multiutente
Se la tua app vuole identificare utenti unici, ad esempio per raccogliere dati e analisi o creare un altro account
associazioni, devi seguire le pratiche consigliate per identificare
per le installazioni uniche. Creando una nuova UUID
all'avvio dell'app per
la prima volta, avrai la certezza di ottenere un ID univoco per il monitoraggio di ogni utente, indipendentemente dal numero
Gli utenti installano la tua app su un singolo dispositivo. In alternativa, puoi salvare un token locale recuperato dal tuo server o utilizzare l'ID registrazioni fornito da Google Cloud Messaging.
Tieni presente che se la tua app richiede uno degli identificatori del dispositivo hardware (ad esempio l'indirizzo MAC del WiFi o il numero SERIAL
), fornirà lo stesso valore per ogni utente perché questi identificatori sono legati all'hardware e non all'utente. Per non parlare dell'altro
i problemi presentati da questi identificatori, come discusso nel documento
Post del blog sulle installazioni di app.
Nuove impostazioni globali
Le impostazioni di sistema sono state aggiornate per supportare più utenti con l'aggiunta di Settings.Global
. Questa raccolta di impostazioni è simile alle impostazioni di Settings.Secure
perché sono di sola lettura, ma viene applicata a livello globale in
tutti gli spazi utente sul dispositivo.
Diverse impostazioni esistenti sono state spostate qui da Settings.System
o Settings.Secure
. Se la tua app è
al momento apporta modifiche alle impostazioni definite in precedenza in Settings.System
(ad es. AIRPLANE_MODE_ON
), dovresti aspettarti che
questa operazione non funzionerà più su un dispositivo con Android 4.2 o versioni successive se tali impostazioni sono
spostato in Settings.Global
. Puoi continuare a leggere le impostazioni in Settings.Global
, ma poiché non sono più considerate sicure per le app, il tentativo di modificarle non andrà a buon fine e il sistema scriverà un avviso nel log di sistema quando esegui l'app su Android 4.2 o versioni successive.
Supporto del layout RTL
Android ora offre diverse API che ti consentono di creare interfacce utente con trasformare l'orientamento del layout per supportare le lingue che utilizzano interfacce utente da destra a sinistra (RTL) e per la lettura come l'arabo e l'ebraico.
Per iniziare a supportare i layout RTL nella tua app, imposta l'attributo android:supportsRtl
sull'elemento <application>
nel file manifest
e imposta il valore “true"
. Una volta attivata questa opzione, il sistema attiverà varie API RTL per visualizzare l'app con layout RTL. Ad esempio, la barra delle azioni mostrerà l'icona e il titolo sul lato destro e i pulsanti di azione a sinistra. Anche i layout che hai creato con le classi View
fornite dal framework verranno invertiti.
Se devi ottimizzare ulteriormente l'aspetto della tua app quando viene visualizzata con un layout RTL, esistono due livelli di ottimizzazione di base:
- Conversione delle proprietà di layout orientate a sinistra e a destra in layout orientati all'inizio e alla fine
proprietà.
Ad esempio, usa
android:layout_marginStart
invece diandroid:layout_marginLeft
eandroid:layout_marginEnd
al posto diandroid:layout_marginRight
.La classe
RelativeLayout
fornisce anche il layout corrispondente per sostituire le posizioni sinistra/destra, ad esempioandroid:layout_alignParentStart
a sostituisciandroid:layout_alignParentLeft
eandroid:layout_toStartOf
anzichéandroid:layout_toLeftOf
. - In alternativa, per fornire un'ottimizzazione completa per i layout RTL, puoi fornire file di layout completamente separati utilizzando il qualificatore della risorsa
ldrtl
(ldrtl
sta per layout-direction-right-to-left}). Ad esempio, puoi salvare i file di layout predefiniti inres/layout/
e i layout ottimizzati per RTL inres/layout-ldrtl/
.Il qualificatore
ldrtl
è ideale per le risorse ricalcabili, in modo da poter fornire grafica orientata nella direzione corrispondente alla direzione di lettura.
Nel framework sono disponibili varie altre API per supportare i layout RTL, ad esempio nella classe View
per implementare i comportamenti appropriati per le visualizzazioni personalizzate e in Configuration
per eseguire query sull'orientamento del layout corrente.
Nota:se utilizzi SQlite e i nomi di tabelle o colonne sono
"solo numero" essere
attenzione: l'utilizzo di String.format(String, Object...)
può causare errori in cui i numeri
sono state convertite nella lingua araba se il dispositivo è stato impostato sulla lingua araba.
Devi utilizzare String.format(Locale,String,Object...)
per assicurarti che i numeri vengano conservati come ASCII. Utilizza anche String.format("%d", int)
anziché String.valueOf(int)
per formattare i numeri.
Frammenti nidificati
Ora puoi incorporare frammenti all'interno di altri frammenti. Questa operazione è utile in una serie di situazioni in cui vuoi inserire componenti dell'interfaccia utente dinamici e riutilizzabili in un componente dell'interfaccia utente che sia esso stesso dinamico e riutilizzabile. Ad esempio, se utilizzi ViewPager
per creare frammenti che scorrono verso sinistra e destra e occupano la maggior parte dello spazio sullo schermo, ora puoi inserire frammenti in ogni pagina del frammento.
Per nidificare un frammento, chiama semplicemente getChildFragmentManager()
nel Fragment
in cui vuoi aggiungerne uno. Viene restituito un FragmentManager
che puoi utilizzare come fai normalmente dall'attività di primo livello
per creare transazioni di frammento. Ad esempio, ecco del codice che aggiunge un frammento dall'interno
un corso Fragment
esistente:
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();
All'interno di un frammento nidificato, puoi ottenere un riferimento al frammento principale chiamando
getParentFragment()
.
Android Support Library ora supporta anche i frammenti nidificati, in modo da poter implementare progetti di frammenti su Android 1.6 e versioni successive.
Nota: non puoi gonfiare un layout in un frammento quando tale layout
include un <fragment>
. I frammenti nidificati sono supportati solo se aggiunti a
in modo dinamico.
Script di rendering
La funzionalità di calcolo di Renderscript è stata migliorata con le seguenti funzionalità:
- Funzionalità intrinseche dello script
Puoi usare le funzionalità intrinseche degli script integrati di Renderscript che implementano operazioni comuni per te, ad esempio:
Blends
Blur
Color matrix
3x3 convolve
5x5 convolve
Per-channel lookup table
Converting an Android YUV buffer to RGB
Per utilizzare uno script intrinseco, chiama il metodo
create()
statico di ogni per creare un'istanza dello script. Poi chiami i metodiset()
disponibili di ogni script intrinseco per impostare gli input e le opzioni necessari. Infine, chiama il metodoforEach()
per eseguire lo script.- Gruppi di script
-
ScriptGroup
ti consentono di concatenare script Renderscript correlati ed eseguirli con una sola chiamata.Utilizza un
ScriptGroup.Builder
per aggiungere tutti gli script al gruppo chiamandoaddKernel()
. Una volta aggiungere tutti gli script, creare le connessioni tra script chiamandoaddConnection()
. Quando hai finito di aggiungere i collegamenti, chiamacreate()
per creare il gruppo di script. Prima di eseguire il gruppo di script, specifica l'inputAllocation
e lo script iniziale da eseguire con il metodosetInput(Script.KernelID, Allocation)
, fornisci l'outputAllocation
in cui verrà scritto il risultato e lo script finale da eseguire consetOutput()
. Infine, richiamaexecute()
per eseguire il gruppo di script. - Script filtro
-
Filtro Script definisce i vincoli sulle API Renderscript esistenti che consentono l'esecuzione del codice risultante su una gamma più ampia di processori (CPU, GPU e DSP). Per creare fileFilterscript, crea
.fs
anziché.rs
e specifica#pragma rs_fp_relaxed
per indicare al runtime di Renderscript che i tuoi script non richiedono una precisione rigorosa in virgola mobile IEEE 754-2008. Questa precisione consente l'azzeramento per le denorme e il arrotondamento verso zero. Inoltre, gli script Filterscript non devono utilizzare tipi incorporati a 32 bit e devono specificare una funzione principale personalizzata utilizzando l'attributo__attribute__((kernel))
perché Filterscript non supporta i puntatori, che vengono definiti dalla firma predefinita della funzioneroot()
.
Nota: anche se il supporto di Filterscript è disponibile nella piattaforma, il supporto per gli sviluppatori sarà disponibile nella release 21.0.1 di SDK Tools.
Per una visualizzazione dettagliata di tutte le modifiche API in Android 4.2, vedi Report Differenze API.