Category

Android

Timber Android: loggare con serenità!

Oggi voglio parlare con voi di un aspetto che ogni sviluppatore, sia mobile che web, ha a che fare ogni giorno. Scrivere ed organizzare i propri log applicativi è importantissimo. Ancora più importante è offuscarli negli ambienti di produzione, sia per questioni di pulizia che per questioni di sicurezza (loggare lo stato di chiamate http con tutti i parametri, quali username, password o secret key ad esempio). Una libreria che ha reso questa gestione più serena in Android è Timber, ed oggi voglio parlarvene!

In Android la logica di decidere quali log tenere in produzione o meno è responsabilità del programmatore. Per un gran periodo della mia carriera, avevo creato una classe “LogUtils” che funzionava da intermediario con il mio codice e la classe android.util.Log. Essa conteneva tutti i metodi per loggare come la relativa classe nativa, ma prima di scriverli controllava se la costante d’ambiente BuildConfig.DEBUG fosse positiva. In caso contrario, non scriveva il log.

Questa grezza logica riusciva si a fare il proprio lavoro, ma non mi dava molte libertà. In alcuni casi mi poteva far comodo tenere dei log in produzione.
Inoltre, dopo anni di sviluppo (e forse anche voi!), comincio ad infastidirmi verso alcuni processi ripetitivi che noi sviluppatori effettuiamo ogni giorno: Ogni volta che dovevo scrivere un log su una classe nuova, la famosissima ed irritante variabile statica TAG mancava ed il perdere quei 10 secondi ogni volta mi urtava il sistema nervoso.

Per tutte queste problematiche ci viene incontro Timber, una libreria Android che ci facilita la scrittura e la logica dei nostri log!

Android Timber, che cosa è

Timber è una piccola libreria Android che contiene dei metodi che facilitano la gestione dei log all’interno dell’applicazione. è possibile infatti “piantare” Timber all’inizio dell’applicazione, e decidere quali log devono essere stampati o meno. Potrete così decidere di offuscare determinati log con la build di produzione e invece stampare qualsiasi informazione in quella di debug. La logica con cui vengono oscurati o meno i log è decisa interamente da voi, dandovi così la più completa libertà, insieme alla semplicità di utilizzo.

Implementazione ed uso di Timber in un applicazione Android

Per importare la libreria nel vostro progetto basterà aggiungere l’implementazione nel vostro gradle:

implementation 'com.jakewharton.4.7.1'

Vi consiglio di controllare la guida nella pagina di Github poichè il numero di versione potrebbe essere aggiornato.
Sincronizzate il progetto ed ecco fatto, siete pronti per “piantare” i vostri log!

Per configurare Timber andrà “piantato” un “albero” (Tree), vale a dire creare una istanza. Di solito il posto migliore è nel OnCreate della vostra classe Application:

public class ExampleApp extends Application {

@Override public void onCreate() {
     super.onCreate();

     if (BuildConfig.DEBUG) {
        Timber.plant(new DebugTree());
     } else {
        Timber.plant(new CrashReportingTree());
     }
}

}

Questo esempio “pianta” un DebugTree in caso si tratti di una build di Debug. In caso di build di produzione, invece, Timber crea un CrashReportingTree.

DebugTree è una classe che si trova all’interno della libreria che permette di loggare tutto. In ambiente di Debug è molto importante loggare qualsiasi cosa, per agevolare sia lo sviluppo che il bug fixing.
In produzione la situazione è molto diversa, vogliamo che i log siano il meno possibile, per motivi di sicurezza.


Ogni applicazione può necessitare diverse logiche di log in produzione: Alcune non vogliono loggare niente, mentre altre solo i log di livello ERROR o di determinate classi. Per avere il pieno controllo sarà necessario creare una classe che estende Timber.Tree ed gestire la logica all’interno del metodo log:

/** A tree which logs important information for crash reporting. */
   private static class CrashReportingTree extends Timber.Tree {
     @Override protected void log(int priority, String tag, @NonNull String message, Throwable t) {

       if (priority == Log.VERBOSE || priority == Log.DEBUG) {
         return;
       }  

       FakeCrashLibrary.log(priority, tag, message);

       if (t != null) {
          if (priority == Log.ERROR) {
             FakeCrashLibrary.logError(t);
       } else if (priority == Log.WARN) {
          FakeCrashLibrary.logWarning(t);
       }
    }
  }
}

In questo caso, qualsiasi log di livello VERBOSE o DEBUG viene completamente ignorato, mentre gli altri vengono gestiti da una logica personalizzata dell’applicazione.

Iniziamo a Timber – loggare!

Ora che abbiamo configurato la nostra libreria, possiamo iniziare a loggare!
La procedura di log è semplicissima! Timber ha gli stessi metodi statici della classe Log di Android, basterà sostituire “Log.METODO” con “Timber.METODO” (Timber.d, Timber.w, Timber.v e così via):

Timber.d("Ciao, sono un log!")

TAG ? No grazie!

Eccoci qui . ad una grande funzionalità di questa libreria! Siete stanchi, ogni volta che loggate in una nuova classe, di creare la solita variabile statica privata TAG?
Nessun problema! Richiamando i metodi di Timber, esso riuscirà ad intuire da quale classe è stato chiamato il metodo e metterà in automatico il nome della classe. Un problema in meno!

Nel caso invece si voglia mettere un TAG personalizzato, è sempre possibile farlo con il seguente modo:

Timber.tag("TagPersonalizzato").d("Ciao sono un log con un tag personalizzato!");

Concatenazione di Stringhe e variabili

Nel caso in cui il testo dei log contiene stringhe e variabili (la maggior parte dei casi), non sarà necessario scrivere “stringa” + variabile, oppure usare String.format().
Timber gestisce la formattazione in maniera automatica:

Timber.d("Ciao, mi chiamo %s %s", firstName, lastName);

Un’ altra funzionalità che ci permettere di perdere meno tempo nella scrittura di log!

Lint, che passione!

All’interno di Timber sono gestite delle regole Lint che ci mostreranno dei warning che potremmo risolvere manualmente o che verranno automaticamente risolte dalla libreria:

  • Numero incorretto di argomenti
  • Argomenti di tipo diverso da quello specificato
  • Lunghezza dei TAG superiori a 23 (lunghezza massima di Android)
  • Metodi che usano ancora Log.* invece di Timber.*
  • Concatenazione di stringhe al posto della formattazione automatica di Timber
  • Uso di log con messaggio nullo o vuoto. Notifica anche i log che contengono come messaggio solo un eccezione

Tutti questi warning possono essere automaticamente risolti da Timber cliccando sulla lampadina gialla.

Spero che il mio articolo vi abbia incuriosito, vi lascio qui il link della pagina di Github. Il mio consiglio è quello di provarlo, la sua semplicità ed immediatezza ha fatto scattare in me amore a prima vista!

Alla prossima,
Buon coding!

Guida DownloadManager: Componenti Jetpack #1

Oggi vi voglio parlare di un componente della raccolta Jetpack di Android, “DownloadManager”, insieme ad una breve panoramica e guida del suo utilizzo.
Potrete consultare un esempio completo attraverso questo repository di Github. Gli snippet di codice successi saranno presi da questo progetto.
Inoltre, è disponibile su PlayStore l’applicazione di prova che ho creato appositamente come supporto a questo articolo.

Guida DownloadManager: Di cosa tratta?

DownloadManager è un servizio di sistema Android che gestisce i download HTTP di lunga/breve durata. Non richiede implementazioni di librerie aggiuntive, poiché si trova all’interno del’ SDK di Android.
Le applicazioni possono richiedere a questo servizio di scaricare un Uri e di salvarlo in uno specifico percorso, che sia privato dell’applicazione o pubblico.

DownloadManager si occuperà infine di gestire il processo in background di download, delle interazioni HTTP e ripartirà dall’inizio in caso di fallimento o di riavvio del dispositivo.

I permessi necessari

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
  • android.permission.INTERNET
    Necessario per le applicazioni per accedere ad internet.
  • (OPZIONALE) android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
    Necessario per usare DownloadManager senza rendere visibile la notifica (DownloadManager.Request.VISIBILITY_HIDDEN) di download del file. Nel caso si lasciasse la notifica visibile, tale permesso non è necessario.

Come potete vedere, l’utilizzo di questo componente non prevede l’utilizzo di particolari permessi (soprattutto quelli catalogati da Android come “pericolosi”).

Come richiedere un download

Per prima cosa, è necessario creare una istanza della classe DownloadManager. Come tutti i servizi di sistema Android, non viene creata un istanza dal costruttore ma viene richiesta dal contesto:

val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager

Ora che abbiamo creato l’oggetto, possiamo inviargli una richiesta di download, creando un oggetto di classe DownloadManager.Request.
Questa classe ha l’obiettivo di contenere tutte le informazioni necessarie a DownloadManager per poter gestire il download di un File:

private fun generateDownloadRequest():DownloadManager.Request{

//Creiamo un oggetto DownloadManager.Request e 
//gli passiamo l'url per il download del file
val request:DownloadManager.Request = DownloadManager.Request(Uri.parse("http://url_file.pdf"))
//Impostiamo il titolo della notifica che verrà visualizzata    
request.setTitle(txt_notification_title.editText?.text.toString())
//Impostiamo la descrizione della notifica che verrà visualizzata        
request.setDescription(txt_notification_description.editText?.text.toString())
//impostiamo la destinazione del file, in questo caso sarà nella cartella privata dell'applicazione "Downloads". Il nome del file sarà testFile
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS,"testFile")
//impostiamo se il download ha il permesso di usare il traffico della rete mobile
request.setAllowedOverMetered(true)
 //impostiamo se il download ha il permesso di scaricare anche in caso fossimo in roaming       
request.setAllowedOverRoaming(true)
 
//Build.VERSION_CODES.N o maggiore: Impostiamo se il 
//download deve partire solo se il dispositivo è in carica         
request.setRequiresCharging(false)
//Build.VERSION_CODES.N o maggiore: Impostiamo se il 
//download deve partire solo se il dispositivo è in
//modalità Idle (inattivo)
request.setRequiresDeviceIdle(false)

//Impostiamo se si visualizza o meno la notifica di download
//
//DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
//Notifica visibile sia durante che a completamento del download
//
//DownloadManager.Request.VISIBILITY_HIDDEN
//Mai visualizzata. Ricordarsi di aggiungere al manifest il permesso
//android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
//
//DownloadManager.Request.VISIBILITY_VISIBLE
//Notifica visibile solo durante il download. A download completato
//scompare
//
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)

  return request
 }

In questo esempio ho cercato di includere tutti i vari parametri che vi può essere utile modificare, con relativa descrizione nei commenti,

Una volta creata la richiesta, sarà possibile passarla al DownloadManager in questo modo:

val id:Long = downloadManager.enqueue(request)

Molto importante è il valore restituito da DownloadManager.enqueue: Si tratta dell’identificativo che il sistema ha assegnato alla richiesta. Sarà importante per capire quando il download è terminato (Sia nel bene che nel male).

Intercettare il completamento del download

Per capire se il download richiesto è terminato è necessario registriare un receiver nel manifest (oppure anche runtime):

<receiver android:name=".receiver.DownloadManagerReceiver">
     <intent-filter>
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
        <action
android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
     </intent-filter>
</receiver>

Le azioni registrate ed inviate da DownloadManager sono:

  • android.intent.action.DOWNLOAD_COMPLETE
    Invia questo evento quando un Download è stato completato.
  • android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED
    Invia questo evento quando l’utente clicca sulla notifica mentre il download è ANCORA in corso.
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast
import com.danielebachicchi.jetpackdownloadmanagerexample.utils.DownloadManagerUtils
import com.danielebachicchi.jetpackdownloadmanagerexample.item.DownloadObject

class DownloadManagerReceiver: BroadcastReceiver() {
 
    override fun onReceive(p0: Context?, p1: Intent?) {
        val action:String? = p1?.action
 
        var downloadID:Long = -1

        if(DownloadManager.ACTION_DOWNLOAD_COMPLETE == action){
            //ritirare l'id del download completato
            downloadID = p1.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1)

            val downloadManager:DownloadManager = p0!!.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                
            val downloadObject: DownloadObject? =
                DownloadManagerUtils.queryDownloadManagerObject(
                    downloadManager,
                    downloadID
                )
            //Ora abbiamo l'oggetto con tutte le 
            //informazioni del download, potete
           //fare tutto quello che volete!

        }else if (DownloadManager.ACTION_NOTIFICATION_CLICKED == action){
            downloadID = p1.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1)

          //Gestite il caso in cui la notifica del 
          //download di downloadID è stata cliccata
          //dall'utente

        }
    }
}
fun queryDownloadManagerObject(downloadManager:DownloadManager, id:Long): DownloadObject?{

           val cursor:Cursor = downloadManager.query(DownloadManager.Query().setFilterById(id))

            var result: DownloadObject? = null
            if (cursor.moveToFirst())
                result = DownloadObject.fromCursor(cursor)


           return result


        }

DownloadManager.query ritorna un Cursor con le informazioni del download richiesto (tramite l’id dell’oggetto, passato da DownloadManager alla richiesta del download). Se ritorna almeno un risultato si procede alla conversione del Cursor ad oggetto:

import android.app.DownloadManager
import android.database.Cursor
import java.util.*

class DownloadObject (val uri:String,
                      val localUri:String,
                      val bytesDownloaded:Long,
                      val bytesTotal:Long,
                      val id:Long,
                      val title:String,
                      val description:String,
                      val date:Date,
                      val mediaProviderUri:String?,
                      val mediaType:String,
                      val reason:String,
                      val status:Int) {



    companion object{
        /*
        --- DownloadManager Row Example ---
        _id : 45
        mediaprovider_uri : null
        destination : 2
        title : Download Test
        description : Downloading a file for testing Download Manager API
        uri : http://ipv4.download.thinkbroadband.com/10MB.zip
        status : 200
        hint : null
        media_type : application/zip
        total_size : 10485760
        last_modified_timestamp : 1565972803944
        bytes_so_far : 10485760
        allow_write : 0
        local_uri : content://downloads/all_downloads/45
        reason : placeholder
         --- End Row ---*/
        fun fromCursor(cursor:Cursor): DownloadObject {
            val uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI))
            
            val localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
            
            val bytesDownloaded = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
            
            val description = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION))
            
            val id = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID))
            
            val date = Date(cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP)))
            
            val mediaProviderUri:String? = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIAPROVIDER_URI))
            
            val mediaType = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE))
            
            val reason = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_REASON))
            
            val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
            
            val title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE))
            
            val bytesTotal = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))

            return DownloadObject(
                uri,
                localUri,
                bytesDownloaded,
                bytesTotal,
                id,
                title,
                description,
                date,
                mediaProviderUri,
                mediaType,
                reason,
                status
            )

        }
    }

    override fun toString(): String {
        return "DownloadObject(\nuri='$uri'\nlocalUri='$localUri'\nbytesDownloaded=$bytesDownloaded\nbytesTotal=$bytesTotal\nid=$id\ntitle='$title'\ndescription='$description'\ndate=$date\nmediaProviderUri=$mediaProviderUri\nmediaType='$mediaType'\nreason='$reason'\nstatus=$status\n)"
    }


}

Questo è un oggetto di utility creato da me con l’obiettivo di racchiudere tutte le informazioni che DownloadManager possiede per un determinato download, con relativo metodo di wrapping dal Cursor.

Guida DownloadManager: il repository Git e l’applicazione di esempio!

Vi consiglio caldamente di consultare il codice del repository Github o scaricare l’applicazione esempio direttamente dal PlayStore (lasciatemi qualche stella se vi è stata almeno un poco utile e lasciate un commento con il vostro parere, mi piacerebbe sentire la vostra opinione)

Anche oggi è tutto, fatemi sapere se questa guida del componente Android DownloadManager vi è stata utile!

Buon codice a tutti voi!

Pixel art in Android: Come implementarla

Vi devo confessare una cosa. Sono un amante della pixel art. Il fascino retrò degli anni 80, suscita in me sempre grandi emozioni.
Implementare la Pixel Art in Android nelle proprie applicazione è semplice, ma bisogna utilizzare qualche piccola accortezza affinché le proprie immagini non vengano deformate.

Antialiasing: L’incubo della pixel art

da quando la tecnologia si è evoluta, la nemesi della pixel art è sempre stata l’Antialiasing.
L’Antialiasing, fatta eccezione per la pixel art, è una cosa positiva.

Quando un immagine dalle piccole dimensioni viene ridimensionata in una più grande, viene applicata, nella maggior parte dei casi, una tecnica per impedire l’ aliasing (“Gradinatura”, “Scalettatura”): esso consiste nell’ammorbidire le linee smussandone i bordi e migliorando l’immagine.
La pixel art si basa invece sulla “Scalettatura”. Essa è improntata sul far vedere all’utente i pixel che realizzano l’opera.
L’antialiasing, applicata su un immagine in pixel art, la trasforma come se fosse patinata (effetto miope senza occhiali per essere più precisi!), creando un forte disagio all’osservatore.

Dithering

Il dithering è una tecnica che aggiunge all’immagine del “rumore”, minimizzando eventuali distorsioni causate dal ridimensionamento dell’immagine.
In realtà questa tecnica viene usata anche per disegnare in pixel art.
La pixel art si basa sul colorare il singolo pixel di un determinato colore. Come è quindi possibile in un immagine creare delle sfumature?
“Ingannando” l’occhio umano con dei “pattern” (disposizione in un certo ordine dei pixel) che simulino questa graduazione:

Esempi di vari pattern di dithering, usati per creare un effetto sfumatura.

Finché il Dithering è un processo deciso volontariamente dall’autore, nessun problema. Quando il dithering è generato automaticamente dai computer per scalare un immagine, può creare delle mutazioni che rendono l’immagine deformata.
Un immagine in pixel art è creata generando delle simmetrie precise tra i vari pixel. Un solo pixel modificato può rovinare l’intera opera.

Visualizzare Pixel Art in Android: L’approccio sbagliato

Proviamo a visualizzare un icona in pixel art come se fosse un immagine come tante, utilizzando una ImageView. L’icona creata da me è di dimensioni 16×16, e la ridimensioneremo a 160dp:

<ImageView
            android:layout_width="160dp"
            android:layout_height="160dp" 
            app:srcCompat="@drawable/sword"
            android:id="@+id/imageView"/>
Visualizzare un icona in pixel art in una ImageView senza nessun accorgimento
Visualizzare un icona in pixel art in una ImageView senza nessun accorgimento

Come vedete, qualcosa non torna. L’immagine sembra opaca. Questo effetto è l’Antialiasing!
Android tenta di smussare le linee, dato che abbiamo aumentato di dieci volte la sua reale dimensione.

Come visualizzare correttamente la pixel art in Android

Per visualizzare correttamente l’immagine, è necessario creare una Bitmap e disabilitare l’antialiasing su di essa. Creiamo nella cartella drawable un xml “sword_pixel_perfect.xml”:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@drawable/sword"
        android:antialias="false"
        android:dither="false"
        android:filter="false"
        >
</bitmap>
  • src
    Specifichiamo l’immagine bersaglio.
  • antialias
    Questa variabile permette la disattivazione/attivazione della tecnica di antialiasing. Impostiamola a false.
  • dither
    Possiamo, con questa impostazione, disattivare i dithering.
  • filter
    FilterBitmap, se abilitato, esegue delle trasformazioni dell’immagine simile all’ antialiasing. Questo parametro si usa quando viene rotata un immagine, in modo tale da ammorbidire le linee.

Ora che abbiamo creato la giusta risorsa, non occorre altro che sostituire l’immagine dell’ ImageView con questo xml:

<ImageView
            android:layout_width="160dp"
            android:layout_height="160dp" 
            app:srcCompat="@drawable/sword_pixel_perfect"
            android:id="@+id/imageView"/>

Ed ecco qua la nostra immagine in pixel art perfettamente visualizzata in una applicazione Android!

Anche per oggi è tutto!
Spero che questa guida vi sia stata utile!
Fatemi sapere cosa ne pensate!

Alla prossima!

Buon codice a tutti!

Camera 2 Helper Library

Sono felice di condividere con voi tutti una libreria che ho creato per la gestione della Camera su Android, sfruttando le nuove API messe a disposizione (Camera2): Camera 2 Helper Library.

Gestire tutto il flusso di apertura/chiusura della Camera è faticoso e ridondante. Ho pensato quindi di creare questa classe la quale, una volta inizializzata, pensa al “lavoro sporco”, permettendoti di focalizzarti sulle logiche successive all’acquisizione dell’immagine!

Cosa è Camera2 Helper library

Camera 2 Helper Library è una libreria per Android che facilita l’utilizzo delle API di Android SDK riguardanti Camera2. Gestisce tutto il flusso di apertura e chiusura della camera, la richiesta del permesso di utilizzo della camera e ti permette di richiamare dei metodi per la cattura dell’immagine.
Richiede una versione minima Android SDK 23.

Una funzionalità aggiuntiva è la Live Mode che permette di processare in background le immagini della Camera in tempo reale. Utile nel caso abbiate bisogno di processare in real-time ciò che la camera sta attualmente vedendo. L’esempio più immediato del suo utilizzo è quello di rilevare automaticamente “Barcode” o “QRCode”: in questo caso la Live Mode fa al caso vostro! Essa vi fornirà, ad intervalli regolari impostati da voi, l’immagine di ciò che la camera sta rilevando.

Dove posso trovarla?

Attualmente Camera 2 Helper Library è in versione alpha ed è possibile visualizzare il codice e leggere la guida su come implementarla nelle proprie applicazione tramite questo link :

https://github.com/Badge87/Camera2Helper

Ovviamente qualsiasi richiesta di implementazione o di risoluzione bug è benvenuta! Il mio obiettivo è quello di migliorarla e perfezionarla, in modo che possa essere di aiuto a molti sviluppatori (oltre che a me stesso :D) che hanno avuto un po’ di problemi durante l’utilizzo di queste API (che, secondo la mia opinione, non sono proprio molto intuitive :P)!
Spero vi sia utile, fatemi sapere cosa ne pensate!

A presto!

Android O : le prime novità per gli sviluppatori!

Da pochi giorni è stata resa disponibile la prima Developer Preview del nuovo Sistema Operativo Android “O” 8.Il nome ufficiale non è ancora reso pubblico, quale nuovo dolce il team di google sceglierà?
Andiamo ad analizzare insieme le prime novità per gli sviluppatori:

Android O: Novità

Limiti Background

Sono stati aggiunti ulteriori limiti automatici su cosa le applicazioni possono fare in background, al fine di ottimizzare la durata della batteria del dispositivo.Le aree toccante sono le seguenti:
  • Broadcast impliciti.
  • Servizi in background.
  • Aggiornamenti della posizione.
Per maggiori dettaglio, vi riporto il link della documentazione ufficiale riguardante i “Limiti dell’esecuzione in background” e “limiti sulla geolocalizzazione in background”.

Canali di Notifica

Android O introduce i canali di notifica , nuove categorie definite all’interno della applicazione per i contenuti delle notifiche.Questa funzionalità permette agli sviluppatori di avere maggior controllo sulle notifiche aggregandole per categorie e modificando il proprio comportamento a livello di gruppo.Fino ad ora lo sviluppatore doveva cambiare il comportamento delle notifiche singolarmente.

Canale Notifiche Android O
Canale Notifiche Android O.

API Riempimento automatico

Android O aggiunge delle API pubbliche per il riempimento automatico dei valori immessi dall’utente (credenziali, informazioni, password…).L’utente infatti potrà scegliere un applicazione “Riempimento automatico” default per il sistema operativo.Gli sviluppatori che vogliono creare un applicazione di riempimento automatico avranno a disposizione queste API per poter sfruttare queste nuove feature.

Nuove funzionalità PIP

 La modalità Picture in Picture di Android permette all’utente di poter continuare a guardare video mentre stanno rispondendo a un messaggio o mentre eseguono altre azioni.
Le applicazioni possono cambiare visualizzazione (dallo stato resume o pause dell’ activity) in modalità PIP quando il sistema operativo lo permette.Potranno così visualizzare le proprie schermate in modalità diversa se la PIP è attivata.

Font resources

Finalmente i fonti sono pienamente supportati all’interno dei xml resources.
Le applicazioni possono ora usare e definire font e famiglie di font negli xml layout. 

Icone Adattive

è possibile creare delle icone adattive le quali verranno visualizzate dal sistema in diverse forme.Il sistema provvederà inoltre ad animarle e potranno essere usate nel launcher, nelle shortcuts, dialog e nella schermata di impostazioni.

Icone Adattive Android O.
Icone Adattive Android O.

Colori Wide-gamut per le applicazioni

Da Android O gli sviluppatori possono sfruttare i nuovi dispositivi che supportano i colori Wide-gamut.
Per poter visualizzare immagini in wide-gamut, le applicazioni dovranno abilitare tale funzionalità all’interno del manifest(per singola activity) e caricare una bitmap con un profilo di colori incorporato(AdobeRGB,Pro Photo RGB…).

Connettività

Android O porta miglioramenti dal punto di vista della connettività.
Il Sistema operativo ora supporta i bluetooth codec LDAC, mentre dal punto di vista del WiFI è stato aggiunto il Wi-Fi Aware, conosciuto precedentemente come NAN (Neighbor Awareness Networking) :
Le applicazioni installate nei dispositivi che hanno le caratteristiche hardware adatte potranno comunicare attraverso Wi-Fi senza la presenza di un accesso ad internet.

Navigazione con tastiera

Ritorna in vita la navigazione con tastiera, per poter supportare anche i SO Chrome OS che potranno installare le applicazioni del PlayStore.

AAudio API

Nuove API per le applicazioni che hanno l’esigenza di lavoro sull’audio in maniera più approfondita e a basso livello. AAudio permette infatti alle applicazioni di di leggere e scrivere data attraverso gli stream.

Miglioramenti WebView

è stata introdotta una nuova modalità opzionale che abilita la multiprocessassione all’interno delle webview, processando il contenuto web in un processo isolato.
In Android O è abilitata di default e sono state aggiunte delle API che permettono di gestire gli errori e i crash.

Java 8 API e ottimizzazioni runtime

Supporto per le API della nuova versione java e ottimizzato il processo di Android Runtime, con miglioramenti raddoppiati in alcuni benchmark.
è possibile scaricare l’immagine di Android O tramite questo link, tenendo presente che questa versione è pensata per un uso di testing e non per un uso quotidiano normale.
Raccomando di approfondire i cambiamenti dell’esecuzione in background delle app che potrebbe impattare in maniera pesante sulle vostre app se non analizzato in tempo.
Buon Coding!
Alla prossima!
Daniele.

Le novità in Android 7.1 per gli sviluppatori

La nuova versione Android 7.1 ha portato alcune interessanti aggiunte all’ SDK che permettono agli sviluppatori di creare applicazioni sempre migliori. Di seguito alcuni dei cambiamenti più importanti.

Novità Android SDK 7.1

  • App Shortcuts

    Gli app shortcuts permettono di eseguire funzioni particolari della propria applicazione direttamente nel launcher, senza aprirla.Eseguendo un long press sull’icona verrà visualizzata una lista di azioni (impostate dallo sviluppatore) che l’utente potrà selezionare.
    Ogni singolo shortcut è un Intent che viene gestito all’interno della applicazione.Questi shortcut possono essere statici, ossia pre-impostati dallo sviluppatore tramite dei file resource, oppure possono essere generati runtime.L’uso degli statici è consigliato per azioni comuni ,sempre presenti e universali , mentre quelli dinamici sono consigliati  per azioni disponibili solo a seguito di qualche impostazione/azione che l’utente ha o meno effettuato/impostato.
    Per info più dettagliate visitate la relativa pagina ufficiale.

  • Supporto Immagini e rich content per tastieria standard

    La tastiera Android (soft Keyboard), fino alle versioni precedenti, accettava solo caratteri unicode per l’invio di emoji.
    Questa versione introduce la possibilità , attraverso le “Commit Content API”, di inviare in maniera standard e universale immagini e rich-content alla tastiera.
    Per info più dettagliate visitate la relativa pagina ufficiale

  • Icone Circolari

    Le applicazione ora posso impostare la propria icona launcher come circolari, la quale sarà supportata e visibili dai dispositivi compatibili (andrà comunque definita la relativa icona no circolare sempre, per supportare tutti i dispositivi).
    Per info in merito alle linee guida per le icone circolare visitare la pagina ufficiale.

  • API per Carrier e app che gestiscono chiamate

    Nuove API accessibili che riguardano carrier e app che gestiscono chiamate :

    • Gestione chiamate con multipli endpoint
    • Impostazioni per CDMA voice privacy
    • Supporto per il Source Type nelle Visual Voicemail
  • Nuovo Intent ACTION_MANAGE_STORAGE

    • Questo nuovo Intent può essere lanciato dalle app per lanciare la schermata di pulizia memoria per liberare spazio del dispositivo. Utile nel caso l’applicazione richiede più spazio di quello attualmente disponibile per eseguire le proprie azioni.
  • Nuove Densità di schermo per dispositivi Wear

    Sono state aggiunte 3 nuove densità per i dispositivi Wear :

    • DENSITY_260
    • DENSITY_300
    • DENSITY_340
Per tutti i cambiamenti che apporta questo aggiornamento fate riferimento a questo articolo ufficiale.
Spero questo breve articolo vi sia piaciuto e sia stato utile.
Buon Coding!
Daniele.

Aggiornamento Android Studio 2.3

è stata rilasciata la nuova versione di Android Studio con nuove funzionalità molto utili, insieme a miglioramenti di velocità e stabilità.

Potete aggiornare il vostro Ambiente direttamente da Android Studio (OSX : Android Studio —> Check for updates ,Windows/Linux : Help —> Check For Updates) oppure scaricare la nuova versione dalla pagina ufficiale.

 Android Studio 2.3

Build

Miglioramenti Instant Run e cambiamenti UI

Il pulsante “Run App” ora riavvia sempre l’applicazione per applicare tutti i cambiamenti del codice che richiedono un riavvio.Il nuovo pulsante “Apply changes” applicherà le modifiche senza riavviare l’ applicazione.Inoltre, è stata ottimizzata la velocità di inizializzazione delle Instant run.

Build Cache

Questa nuova funzionalità è molto interessante! Disabilitata per default, permette ad Android Studio di tenere in memoria le build precedenti, rendendo le future compilazioni più veloci.Stanchi di minuti e minuti di compilazione? Io si, proverò sicuramente questa ottimizzazione!.

 Design

Supporto nel Constrain Layout per concatenazione e ratio

Con questa versione possiamo considerare il Constrain Layout stabile.è possibile concatenare più view insieme bidirezionalmente per formare un group con un unica dimensione.Più difficile spiegarlo che applicarlo!Molto comodo quando abbiamo bisogno di piazzare due o più view insieme ma vogliamo fargli occupare tutto lo spazio vuoto.
Constrain Layout ora supporta il ridimensionamento mantenendo la ratio dell’elemento ridimensionato!

Layout Editor Palette

è stato aggiornato l’editor delle palette nella schermata di modifica layout.è possibile ora cercare, ordinare e filtrare tutti i widget per il proprio layout, ma non solo!Verrà visualizzata anche una piccola anteprima del widget selezionato.Una aggiunta di certo non fondamentale, ma molto carina!

Attributi Layout Preferiti

Questa nuova funzionalità potrebbe spingermi ad usare molto di più l’editor visuale dei layout invece che dell’editing xml.Per ogni widget è possibile salvare degli attributi come favoriti e compariranno in una lista più “minimale” della colonna Properties.Fino ad ora ogni volta nell’editor visuale dovevi scorrerti tutte le proprietà del widget, ciò faceva perdere più tempo dell’aggiunta della stessa proprietà via xml.

Supporto Format WebP

Il formato WebP è un formato di compressione sviluppato da Google con l’obiettivo di ottimizzare il caricamento di file a discapito della qualità.Android studio ora permette di generare dagli asset .png del progetto il relativo WebP, permettendo così al vostro apk di essere più leggero.Viene fornito inoltre una finestra che vi darà una anteprima del WebP generato in cui è possibile vedere direttamente le differenze rispetto al png originale.Molto comodo per capire se non ci sono conseguenze strane nella conversione.Sono curioso di vedere i cambiamenti di dimensione dei miei apk!

Aggiornamento Wizard delle Material Icon

Lo wizard delle Material Icon è stato aggiornato, ora è possibile ricercare e filtrare le icone in maniera più veloce.Inoltre sono state aggiunte le varie categorie delle iconset.
  • Develop
    • Lint Baseline
I vari warning lint possono ora essere targati come “basilari” per il progetto selezionato.In questo modo, verrano visualizzati come warning solamente quelli nuovi.Questo può essere molto utile se nel progetto vi sono dei warning per compatibilità legacy, ma il vostro desiderio è di focalizzarsi solamente su nuovi warning.
  • Assistente AppLinks
Questo nuovo assistente è molto utile:PErmette di creare nuovi intent filters per i propri URLs,impostare l’associazione al proprio sito attraverso un relativo file e testare il supporto di questi URLs.
è possibile accedere a questo assistente tramite Tools —> AppLink Assistant.
  • Aggiornamento Templates
Tutti i temprate Android che usavano RelativeLayout ora sono stati sostituiti con ConstraintLayout.
  • Aggiornamento Piattaforma IntelliJ
Sono stati inclusi gli aggiornamenti di IntelliJ 2016.2 . Qui potete trovare le relative funzionalità/miglioramenti della piattaforma.

 Test

Copia/Incolla Emulatore Android – Sistema Operativo

è ora possibile fare copia/incolla dall’emulatore android al sistema operativo del pc e viceversa, utility che, a mio parere, ritengo comodissima, facendo risparmiare in alcuni casi molto tempo.Questa funzionalità è disponibile per le immagini degli emulatori x86 Google API con livello API 19 (Android 4.4 Kitkat) e superiore .

Android Emulator command Line Tools

Da android SDK tools 25.3 è stato spostato “emulator” dall’SDK Tools in una cartella emulator separata.è stato deprecato il comando “android avd” per far stazione al nuovo comando “avdmanager
Per Informazioni aggiuntive e più dettagliate,fate riferimento qui .
Alla prossima!

Guida DBFlow : prima parte

Un elemento che ritengo essenziale per lo sviluppo delle mie applicazioni è una corretta organizzazione e gestione del Database. Estremamente importante è una gestione efficace, veloce e più automatica possibile.Creazione dei Data Transfer Object (dto),relativi controller sono dei compiti molto meccanici e ripetitivi, proprio per questo vi può essere una probabilità di errore nel crearli ed, essendo delle creazioni le quali la maggior parte delle volte sono ripetitive , è sempre meglio automatizzare tutto l’automatizzatile , evitando così molti errori “umani”.
Molte librerie di Object-relational-mapping (DTO) ci vengono in nostro soccorso. Queste librerie si occupano, oltre a gestire le varie connessioni al nostro database localesi assumono al responsabilità di automatizzare la creazione del database, tabelle e dto.
Un altra funzionalità che ritengo importantissima è il query builder, che permette di creare query per interrogare il DB ad “oggetti”,senza scrivere (ma comunque possibile come alternativa) nessuna query nativa.
Oggi analizzeremo una libreria che uso nella maggior parte dei miei progetti Android, la quale mi permette di perdere il meno tempo possibile durante la creazione della struttura/interfacciamento con il database, riuscendo così a concentrarmi su altri aspetti dello sviluppo .
Nel mondo Android esistono varie librerie ORM,in questo articolo vi parlerò di una in particolare che uso in tutti i miei progetti : DBFlow.
In questa parte descriverò come configurare il proprio progetto e il proprio database con DBFLow.

Configurazione Progetto

Per prima cosa è necessario aggiungere le dipendenze delle librerie di DBFLow.
Aggiungere al file build.gradle del progetto il relativo repository :
 
allprojects { 
    repositories { 
        maven { url "https://www.jitpack.io" } 
    } 
} 
Successivamente aggiungere la dipendenza al build.gradle dell’applicazione:
apply plugin: 'com.android.application'

def dbflow_version = "3.1.1"

dependencies {
    ...

    //DBFLow Dependenies
    compile "com.github.Raizlabs.DBFlow:dbflow-core:$dbflow_version}"
    compile "com.github.Raizlabs.DBFlow:dbflow:$dbflow_version}"
}

Per praticità, aggiungo ad inizio pagina la variabile che indica la versione di DBFLOW così, in caso di aggiornamento, non rischio di sbagliare non aggiornando tutti le relative dipendenze.

Dopo una sincronizzazione del progetto, siete pronti a poter usare la libreria!

Creazione e inizializzazione Database

Passiamo ora alla creazione del database, per la creazione del database, create una classe ,nel mio caso nominata “MainDatabase” , che si occuperà di configurare il proprio database:
MainDatabase.java
@Database(name = MainDatabase.DATABASE_NAME, version = MainDatabase.VERSION)
public class MainDatabase {

    public static final String DATABASE_NAME = "db_app";
    public static final int VERSION = 1;


    public static class General{
        public static final String COLUMN_NAME_ROW_ID = "rowID";
    }

    public static class Game{
        public static final String TABLE_NAME = "player";
        public static final String COLUMN_NAME_NAME = "name";
        public static final String COLUMN_NAME_RELEASE_DATE = "release_date";

    }
}
Per associare questa classe al database,è necessaria solamente la annotazione @Database,in cui va specificato il nome del database (senza .sqlite) e la versione del database, necessaria per future migrazioni/aggiornamenti del Database (lo vedremo più avanti).
Per comodità personale all’interno di questa classe creo una classe statica per ogni tabella del mio database per “variabilizzare” i nomi delle relative colonne.
Come ultimo passo, è necessario inizializzare la libreria.Il posto migliore per inizializzala è all’interno della propria classe Application . Create la classe che estende Application e inizializzate la libreria all’interno dell OnCreate :
 
Mainapplication.java
public class MainApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        FlowManager.init(new FlowConfig.Builder(this).build());
        if(BuildConfig.DEBUG)
            FlowLog.setMinimumLoggingLevel(FlowLog.Level.V);
    }
}
FlowManager.init() è il metodo che si occupa dell’inizializzazione di DBFLow. setMinimumLoggingLevel è un utility per vedere i vari log della libreria.
Per ultima cosa associamo questa classe come Application dell’applicazione.Per fare ciò modifichiamo il file manifest.xml :
<application android:name=".core.MainApplication” ... >
Perfetto,all’apertura della applicazione controllerà se il database esiste esse non fosse presente ,verrà creato .
Di seguito il link del progetto guida che ho creato.
Nella prossima parte descriverò la creazione delle varie tabelle dai bean java!
Alla Prossima!
Daniele.