Livello di difficoltà: medioVersione SDK utilizzata: >1.5Link al file compresso del progetto eclipse: file in allegatoNella realizzazione di interfacce su android vi sarete sicuramente accorti che, quando ruotiamo di 90° il nostro dispositivo, l'activity viene distrutta e successivamente ricreata.
Quando si ruota lo schermo il comportamento di default del sistema operativo android è quello di chiamare in successione onSaveInstanceState, onPause, onStop, onDestroy (insomma, un normale shutdown dell'activity) ed infine viene chiamato
onCreate per ricreare l'activity.
(
ActivityLifecycle)
Come è facile dedurre, il metodo onCreate non è il migliore punto per eseguire le nostre inizializzazioni, in quanto probabilmente non vorremo che i nostri dati vengano reinizializzati ogni volta che ruotiamo lo schermo.
Lo scopo di questo tutorial è quello di fornire delle indicazioni su come e in quale modo possiamo eseguire le operazioni di inizializzazione senza aver problemi al momento della rotazione dello schermo.
Esistono varie soluzioni al problema:
1)La prima possibilità che abbiamo è quella di rimuovere il problema alla radice:
Facciamo in modo che quando ruotiamo lo schermo, il nostro layout non reagisca e rimanga portrait o landscape. Un orientamento fisso.
Diciamo che questa non è proprio una soluzione

ma ad ogni modo, se vogliamo implementarla, dobbiamo aggiungere l'
attributo screenOrientation all'
elemento activity (ogni activity ha la sua configurazione):
...
<activity
android:name=".Demo"
android:label="@string/app_name"
android:screenOrientation="portrait">
...In questo modo l'activity è forzata ad usare soltanto l'orientamento portrait. Chiaramente possiamo impostare l'activity in modo da restare landscape.
Veniamo a soluzioni un po' più raffinate

Prendiamo un esempio pratico: vogliamo che quando la nostra applicazione parte, una variabile "data" viene inizializzata e una textView viene impostata con il suo valore.
Quando giriamo lo schermo vogliamo che questo valore rimanga lo stesso e sia sempre presente a schermo.
Ok, volendo possiamo dare un valore di default alla variabile inizializzandola a livello di dichiarazione della variabile come field della classe. Ma questo non è lo scopo... la maggior parte delle inizializzazioni non possono essere eseguite fuori da un metodo (ad esempio l'aggiunta di un elemento un un arraylist).
2)Il framework ci da la possibilità di rendere sensibile un'activity ad un cambio di configurazione, in pratica ad ogni cambio di configurazione (tipo di cambio impostabile) il metodo
onConfiguratioChanged verrà chiamato al posto della "sequenza di shutdown" citata in precendeza.
Procediamo modificando il manifest aggiungento un attributo configChange alle activity sulle quali vogliamo applicare questo metodo:
...
<activity
android:name=".Demo"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
...In questo modo il metodo onConfigurationChanged verrà chiamato quando l'orientamento del nostro dispositivo cambierà oppure quando estraiamo/nascondiamo la tastiera fisica (se presente ovviamente). All'interno del nostro codice potremmo lavorare nel modo seguente:
public class Demo extends Activity {
TextView tv;
GregorianCalendar date;
SimpleDateFormat sdf;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("Demo", "onCreate");
//facciamo le nostre inizializzazioni
date=new GregorianCalendar();
sdf=new SimpleDateFormat("dd/MM/yy HH:mm:ss");
//impostiamo layout e views
setUpViews();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.v("Demo", "onConfigurationChange");
//impostiamo layout e views
setUpViews();
}
private void setUpViews(){
//tramite la struttura a cartelle layout/layout-land verrà impostato il layout opportuno
setContentView(R.layout.main);
tv=(TextView)findViewById(R.id.myTv);
tv.setText("Applicazione partita al: "+sdf.format(date.getTime()));
//qui andrebbero impostati anche i vari listener
}
}
Vediamo ora invece un altra possibilità che abbiamo per gestire questo tipo di situazioni.
A mio modo di vedere questa è la migliore
3)Creiamo una classe che estende Application, facciamo un override del metodo onCreate e aggiungiamo questa classe al manifest.
Il metodo onCreate sulla classe appena creata, sarà il primo metodo chiamato quando facciamo partire la nostra applicazione.
Questo risulta essere il punto adatto per eseguire tutte le inizializzazioni di cui necessitiamo. Esponiamo questa classe tramite un Singleton, di modo da poter accedere ai nostri dati. Incapsuliamo questi dati tramite dei "getters" e dei "setters":
public class MyApplication extends Application {
private GregorianCalendar date;
//singleton design pattern
static MyApplication instance;
public static MyApplication getInstance(){
if(instance==null){
Log.v("MyApplication", "instance created");
instance=new MyApplication();
}
Log.v("MyApplication", "instance returned");
return instance;
}
@Override
public void onCreate() {
super.onCreate();
Log.v("MyApplication", "onCreate");
MyApplication myApp=getInstance();
myApp.setDate(new GregorianCalendar());
}
public void setDate(GregorianCalendar date) {
this.date = date;
}
public GregorianCalendar getDate() {
return date;
}
}...
<application
android:name=".MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name">
...ora nella nostra applicazione non dovremo piu' preoccuparci degli inconvenienti legati alla rotazione e al richiamo di onCreate, in quanto l'accesso ai dati viene fatto tramite dei "getters" sul modello dati creato nella classe MyApplication. Questi dati potranno essere stati appena inizializzati dal onCreate di Application oppure già modificati tramite i "setters".
public class Demo extends Activity {
MyApplication myApp=MyApplication.getInstance();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("Demo", "onCreate");
setContentView(R.layout.main);
GregorianCalendar date=myApp.getDate();
SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yy HH:mm:ss");
TextView tv=(TextView)findViewById(R.id.myTv);
tv.setText("Applicazione partita al: "+sdf.format(date.getTime()));
}
}
Spero che tutto ciò vi sia utile

Un Saluto.
Qlimax