Livello API: 17
Android 4.2 (JELLY_BEAN_MR1
) è un aggiornamento della release Jelly Bean che offre nuove funzionalità a utenti e sviluppatori di app. Questo documento offre un'introduzione alle nuove API
più importanti e utili per gli sviluppatori.
In qualità di sviluppatore di app, devi scaricare la piattaforma SDK e l'immagine di sistema Android 4.2 da SDK Manager il prima possibile. Se non hai un dispositivo con Android 4.2 su cui testare la tua app, utilizza l'immagine di sistema Android 4.2 per testare l'app con l'emulatore Android. Successivamente, crea le tue app sulla 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"
, installarla su un'immagine di sistema Android 4.2, testarla e pubblicare un aggiornamento con questa modifica.
Puoi
utilizzare le API in Android 4.2 e al contempo supportare le versioni precedenti aggiungendo
al tuo codice condizioni che verificano il livello API di sistema prima di eseguire
API non supportate da minSdkVersion
.
Per scoprire di più sul mantenimento della compatibilità con le versioni precedenti, consulta la sezione Creazione di UI compatibili con le versioni precedenti.
Per ulteriori informazioni su come funzionano i livelli API, consulta Che cos'è il livello API?
Importanti cambiamenti di comportamento
Se hai già pubblicato un'app per Android, tieni presente le seguenti 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 ha effetto solo se imposti
android:targetSdkVersion
oandroid:minSdkVersion
su 17 o un valore superiore. In caso contrario, il valore predefinito è sempre“true"
anche se il sistema operativo è 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 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 precisa), il sistema non fornirà una stima della posizione dell'utente più precisa di un isolato.
- Alcune impostazioni del dispositivo definite da
Settings.System
ora sono 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 andrà a buon fine 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 che sono state spostate suSettings.Global
se viene eseguita su Android 4.2 e versioni successive. - Se la tua app utilizza
WebView
, Android 4.2 aggiunge un ulteriore livello di sicurezza che ti consente di associare JavaScript al tuo codice Android in modo più sicuro. Se impostitargetSdkVersion
su 17 o un numero superiore, ora devi aggiungere l'annotazione@JavascriptInterface
a qualsiasi metodo che vuoi rendere disponibile a JavaScript (anche il metodo deve essere pubblico). Se non fornisci l'annotazione, il metodo non è accessibile da una pagina web inWebView
su Android 4.2 o versioni successive. Se impostitargetSdkVersion
su 16 o su un valore inferiore, l'annotazione non è obbligatoria, ma ti consigliamo di aggiornare la versione di destinazione e aggiungere l'annotazione per maggiore sicurezza.Scopri di più sull'associazione del codice JavaScript al codice Android.
Daydream
Daydream è una nuova modalità salvaschermo interattiva per dispositivi Android. Si attiva automaticamente quando il dispositivo viene inserito in un dock o quando il dispositivo rimane inattivo mentre è collegato a un caricabatterie (anziché spegnere lo schermo). Daydream mostra un sogno alla volta. Può trattarsi di un display passivo puramente visivo che si chiude al tocco o di essere interattivo e reattivo per tutta la gamma di eventi di input. I tuoi sogni vengono eseguiti nel processo della tua app e hanno accesso completo al toolkit dell'interfaccia utente di Android, incluse visualizzazioni, layout e animazioni, quindi sono più flessibili e potenti rispetto agli sfondi animati o ai widget delle app.
Puoi creare un sogno per Daydream implementando una sottoclasse di DreamService
. Le API DreamService
sono
progettate per essere simili a quelle di Activity
. Per specificare l'interfaccia utente per il tuo sogno, trasmetti un ID risorsa di layout o View
a setContentView()
in qualsiasi momento dopo aver creato una finestra, ad esempio dal callback onAttachedToWindow()
.
La classe DreamService
fornisce altri importanti metodi di callback del ciclo di vita oltre alle API Service
di base, come onDreamingStarted()
, onDreamingStopped()
e onDetachedFromWindow()
.
Non puoi avviare un'istanza DreamService
dalla tua
app, poiché viene avviata automaticamente dal sistema.
Se il tuo sogno è interattivo, puoi avviare un'attività dal sogno per indirizzare l'utente all'interfaccia utente completa dell'app per ottenere maggiori dettagli o controlli. Puoi utilizzare finish()
per terminare il sogno e consentire all'utente di vedere la 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"
. Ecco alcuni esempi:
<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>
In DreamService
, esistono altri metodi
utili da tenere a mente:
setInteractive(boolean)
controlla se il sogno riceve eventi di input o esce immediatamente dopo l'input dell'utente. Se il sogno è interattivo, l'utente può utilizzare i pulsanti Indietro o Home per uscire dal sogno 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, il display si attenua per segnalare all'utente che il timeout per inattività si sta avvicinando. La chiamata a
setScreenBright(true)
ti consente invece di impostare il display alla luminosità abituale.
Per saperne di più, consulta la documentazione di DreamService
.
Display secondari
Android ora consente alla tua app di mostrare contenuti esclusivi su schermate aggiuntive collegate al dispositivo dell'utente tramite una connessione cablata o Wi-Fi.
Per creare contenuti univoci per un display secondario, estendi la classe Presentation
e implementa il callback onCreate()
. All'interno di
onCreate()
, specifica la tua UI per il display secondario
chiamando 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 in cui puoi visualizzare il tuo Presentation
, utilizza l'API DisplayManager
o MediaRouter
. Sebbene le API DisplayManager
consentano di enumerare più display che possono essere connessi contemporaneamente, in genere è consigliabile usare 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 passalo
ROUTE_TYPE_LIVE_VIDEO
. Viene restituito un oggetto MediaRouter.RouteInfo
che descrive il percorso attualmente selezionato dal sistema per le presentazioni video. Se MediaRouter.RouteInfo
non è null, chiama
getPresentationDisplay()
per ottenere il Display
che rappresenta il display collegato.
Puoi quindi visualizzare la presentazione passando l'oggetto Display
a un costruttore per la tua classe Presentation
. La presentazione ora
verrà visualizzata sul display secondario.
Per rilevare in fase di runtime quando è stato connesso un nuovo display, crea un'istanza di MediaRouter.SimpleCallback
in cui implementi il metodo di callback onRoutePresentationDisplayChanged()
, che il sistema chiamerà quando viene collegato un nuovo display di presentazione. Quindi registra MediaRouter.SimpleCallback
passandolo a MediaRouter.addCallback()
insieme al tipo di percorso ROUTE_TYPE_LIVE_VIDEO
. Quando ricevi una chiamata al numero onRoutePresentationDisplayChanged()
, chiama il numero MediaRouter.getSelectedRoute()
come indicato sopra.
Per ottimizzare ulteriormente l'UI di Presentation
per le schermate secondarie, puoi applicare un tema diverso specificando l'attributo android:presentationTheme
nella sezione <style>
che hai applicato alla tua applicazione o attività.
Tieni presente che gli schermi collegati al dispositivo dell'utente spesso hanno dimensioni maggiori e probabilmente una densità diversa. Poiché le caratteristiche dello schermo possono variare, dovresti fornire risorse ottimizzate specificamente per questi display. Se devi richiedere risorse aggiuntive da Presentation
, chiama getContext()
.getResources()
per ottenere l'oggetto Resources
corrispondente al display. In questo modo
vengono fornite le risorse dell'app appropriate per le dimensioni e la densità dello schermo del display secondario.
Per ulteriori informazioni e alcuni esempi di codice, consulta la documentazione della classe Presentation
.
Widget schermata di blocco
Android ora consente agli utenti di aggiungere widget delle app alla schermata di blocco. Per rendere disponibile il widget per l'utilizzo nella schermata di blocco, aggiungi l'attributo android:widgetCategory
al file XML che specifica AppWidgetProviderInfo
. Questo attributo supporta due valori: home_screen
e keyguard
. Per impostazione predefinita, l'attributo è impostato su home_screen
, pertanto gli utenti possono aggiungere
il widget dell'app alla schermata Home. Se vuoi che il widget dell'app sia disponibile anche nella schermata di blocco, aggiungi il valore keyguard
:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" ... android:widgetCategory="keyguard|home_screen"> </appwidget-provider>
Devi inoltre specificare un layout iniziale per il widget dell'app nella schermata di blocco utilizzando
l'attributo android:initialKeyguardLayout
. Funziona come android:initialLayout
, in quanto fornisce un layout che può essere visualizzato immediatamente fino a quando il widget dell'app non viene inizializzato e può aggiornarlo.
Per ulteriori informazioni sulla creazione di widget delle app per la schermata di blocco, incluse le dimensioni corrette del widget dell'app nella schermata di blocco, consulta la guida Widget app.
Più utenti
Android ora consente più spazi utente sui dispositivi condivisibili come i tablet. Ogni utente di un dispositivo dispone del proprio insieme di account, app, impostazioni di sistema, file e qualsiasi altro dato associato all'utente.
In qualità di sviluppatore di app, non devi fare nulla per far sì che la tua app funzioni correttamente con più utenti su un singolo dispositivo. Indipendentemente dal numero di utenti presenti su un dispositivo, i dati salvati dalla tua app per un determinato utente vengono mantenuti separati da quelli salvati dall'app per altri utenti. Il sistema tiene traccia dei dati utente appartenenti al processo utente in cui è in esecuzione l'app e fornisce alla tua app l'accesso 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 nello spazio di archiviazione interno o esterno dell'utente, questi dati sono accessibili solo quando l'utente è in esecuzione.
Per assicurarti che la tua app funzioni correttamente in un ambiente multiutente, non fare riferimento alla directory interna dell'app o alla posizione di archiviazione esterna utilizzando percorsi hardcoded e utilizza sempre le API appropriate:
- Per accedere alla memoria interna, usa
getFilesDir()
,getCacheDir()
oopenFileOutput()
. - Per accedere all'unità di archiviazione esterna, usa
getExternalFilesDir()
ogetExternalStoragePublicDirectory()
.
Indipendentemente dall'API che utilizzi per salvare i dati di un determinato utente, i dati non saranno accessibili durante l'esecuzione con un utente diverso. Dal punto di vista dell'app, ogni utente utilizza un dispositivo completamente separato.
Identificazione degli utenti in un ambiente multiutente
Se la tua app vuole identificare utenti unici, ad esempio per raccogliere dati di analisi o creare altre associazioni di account, segui le best practice consigliate per identificare installazioni univoche. Creando un nuovo UUID
quando la tua app viene avviata per la prima volta, hai la certezza di ottenere un ID univoco per il monitoraggio di ciascun utente, indipendentemente dal numero di utenti che installano la tua app su un singolo dispositivo. In alternativa, puoi salvare un token locale recuperato dal tuo server o utilizzare l'ID di registrazione fornito da Google Cloud Messaging.
Tieni presente che se la tua app richiede uno degli identificatori del dispositivo hardware (ad esempio l'indirizzo MAC Wi-Fi o il numero SERIAL
), forniranno lo stesso valore per ogni utente perché questi identificatori sono associati all'hardware e non all'utente. Per non parlare degli altri problemi
introdotti da questi identificatori, come discusso nel post del blog Identificazione
delle 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
in quanto sono di sola lettura, ma viene applicata globalmente a tutti gli spazi utente del dispositivo.
Diverse impostazioni esistenti sono state trasferite qui da Settings.System
o Settings.Secure
. Se l'app sta apportando modifiche a impostazioni precedentemente definite in Settings.System
(ad esempio AIRPLANE_MODE_ON
), ciò non dovrebbe più funzionare su un dispositivo con Android 4.2 o versioni successive se queste impostazioni sono state spostate su Settings.Global
. Puoi continuare a leggere le impostazioni disponibili in Settings.Global
. Tuttavia, poiché queste impostazioni non sono più considerate sicure per la modifica delle app, se tenti di farlo non verrà eseguita automaticamente e il sistema scriverà un avviso nel log di sistema quando esegui l'app su Android 4.2 o versioni successive.
Supporto layout RTL
Android ora offre diverse API che ti consentono di creare interfacce utente che trasformano agevolmente l'orientamento del layout per supportare le lingue che utilizzano UI da destra a sinistra (RTL) e direttive di 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 impostalo “true"
. Dopo l'attivazione, il sistema abiliterà varie API RTL per visualizzare la tua app con i layout RTL. Ad esempio, la barra delle azioni mostrerà l'icona e il titolo a destra e i pulsanti di azione a sinistra; inoltre, verranno invertiti tutti i layout che hai creato con le classi View
fornite dal framework.
Se hai bisogno di ottimizzare ulteriormente l'aspetto dell'app quando viene visualizzata con un layout RTL, i livelli di base di ottimizzazione sono due:
- Converti le proprietà di layout orientate a sinistra e a destra in proprietà di layout con orientamento iniziale e finale.
Ad esempio, utilizza
android:layout_marginStart
al posto diandroid:layout_marginLeft
eandroid:layout_marginEnd
al posto diandroid:layout_marginRight
.La classe
RelativeLayout
fornisce anche gli attributi di layout corrispondenti per sostituire le posizioni a sinistra/destra, ad esempioandroid:layout_alignParentStart
per sostituireandroid:layout_alignParentLeft
eandroid:layout_toStartOf
anzichéandroid:layout_toLeftOf
. - In alternativa, per un'ottimizzazione completa dei layout RTL, puoi fornire file di layout completamente separati
utilizzando il qualificatore delle risorse
ldrtl
(ldrtl
sta per layout-direction-right-to-left}). Ad esempio, puoi salvare i file di layout predefiniti inres/layout/
e i layout ottimizzati RTL inres/layout-ldrtl/
.Il qualificatore
ldrtl
è ottimo per le risorse disegnabili, in modo da poter fornire immagini orientate nella direzione corrispondente alla direzione di lettura.
Nel framework sono disponibili altre API per supportare i layout RTL, ad esempio nella classe View
per implementare i comportamenti corretti per le viste personalizzate e in Configuration
per eseguire query nella direzione attuale del layout.
Nota: se utilizzi SQlite e hai nomi di tabelle o colonne di tipo "solo numero", fai attenzione: l'utilizzo di String.format(String, Object...)
può causare errori in cui i numeri sono stati convertiti negli equivalenti arabi se sul dispositivo è stata impostata la 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 la formattazione dei numeri.
Frammenti nidificati
Ora puoi incorporare frammenti all'interno di questi ultimi. Ciò è utile per una serie di situazioni in cui vuoi posizionare componenti dell'interfaccia utente dinamici e riutilizzabili in un componente dell'interfaccia utente 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 nella pagina di ogni frammento.
Per nidificare un frammento, basta chiamare getChildFragmentManager()
sul Fragment
in cui vuoi aggiungere un frammento. Questo restituisce un valore FragmentManager
che puoi utilizzare come fai normalmente dall'attività di primo livello
per creare transazioni con frammenti. Ad esempio, ecco alcuni codici che aggiungono un frammento dall'interno di una classe 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();
Dall'interno di un frammento nidificato, puoi ottenere un riferimento al frammento padre chiamando getParentFragment()
.
La libreria di assistenza Android ora supporta anche i frammenti nidificati, quindi puoi implementare progettazioni di frammenti nidificate su Android 1.6 e versioni successive.
Nota: non puoi gonfiare un layout in un frammento se questo include un <fragment>
. I frammenti nidificati sono supportati solo se aggiunti a un frammento in modo dinamico.
RenderScript
La funzionalità di calcolo di Renderscript è stata migliorata con le seguenti caratteristiche:
- Funzionalità intrinseche per lo script
Puoi utilizzare le funzionalità intrinseche degli script integrati di Renderscript per implementare 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 script intrinseco per creare un'istanza dello script. Quindi chiama 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
-
Gli
ScriptGroup
consentono di concatenare script Renderscript correlati ed eseguirli con un'unica chiamata.Utilizza un
ScriptGroup.Builder
per aggiungere tutti gli script al gruppo chiamando il numeroaddKernel()
. Dopo aver aggiunto tutti gli script, crea le connessioni tra loro chiamandoaddConnection()
. Dopo aver aggiunto le connessioni, 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)
e fornisci l'output inAllocation
in cui verrà scritto il risultato e lo script finale da eseguire consetOutput()
. Infine, chiamaexecute()
per eseguire il gruppo di script. - Script filtro
-
Filtroscript 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 file Filtroscript, crea file
.fs
anziché.rs
e specifica#pragma rs_fp_relaxed
per indicare al runtime di Renderscript, i tuoi script non richiedono una precisione in virgola mobile rigorosa IEEE 754-2008. Questa precisione consente lo svuotamento a zero per i denorm e il arrotondamento a zero. Inoltre, gli script di filtro non devono utilizzare tipi integrati a 32 bit e devono specificare una funzione root personalizzata utilizzando l'attributo__attribute__((kernel))
, in quanto il filtroscript non supporta i puntatori, che sono definiti dalla firma predefinita della funzioneroot()
.
Nota: sebbene il supporto di Filtroscript sia nella piattaforma, l'assistenza per gli sviluppatori sarà disponibile nella release 21.0.1 di SDK Tools.
Per una visualizzazione dettagliata di tutte le modifiche all'API in Android 4.2, consulta il report Differenze API.