martedì 18 dicembre 2012

Sviluppare un'applicazione Android con Preferences


Introduzione

In questo post spiegherò come sviluppare un'applicazione Android per permettere all'utente di configurare alcuni parametri tramite l'API Preferences. Con questa API si possono visualizzare e salvare alcune impostazioni editate dall'utente; impostazioni che possono essere recuperate in un secondo momento,
così da poter utilizzare questi dati per cambiare il comportamento della nostra
applicazione.

Premesse 

In questo post creerò un'applicazione Android che ha il semplice scopo di visualizzare i dati delle preferenze che l'utente ha editato. Inoltre farò vedere come creare un menù con l'elenco dei dati personalizzabili dall'utente, inserendo il tutto nei file di layout (cioé evitando di inserire le impostazioni nel codice Java).
Per l'usò che ne farò, l'SDK di riferimento sarà la 11 (Honeycomb) o successiva, inoltre parto dal fatto che sappiate già sviluppare semplici applicazioni Android.

Cosa Serve

Tutto ciò che serve per l'utilizzo di Preferences è già contenuto nell'SDK di Android, quindi non abbiamo bisogno d'altro che dell'IDE messo a disposizione da Google.

Preferences.xml


La definizione degli elementi da visualizzare nel menù di configurazione è contenuta
in un file xml, come avviene per le Activities. Ogni elemento editabile è identificato
dall'attributo android:key, una chiave di tipo String, tramite il quale possiamo
recuperare il valore inserito dall'utente.
L'elemento root di questo file è PreferenceScreen che definisce il layout vero e
proprio.
I singoli elementi di inserimento sono:
  • CheckBoxPreference: checkbox che rappresenta un valore booleano
  • EditTextPreference: visualizza un EditText per l'inserimento di un testo libero
  • ListPreference: visualizza una lista selezionabile dall'utente
  • MultiSelectListPreference: come la precedente, ma permette la selezione di più righe
  • RingtonePreference: permette la selezione di una suoneria presente sul dispositivo
  • SwitchPreference: simile a CheckBoxPreference, solo con l'effetto a "interruttore"
Oltre a questi è presente un elemento separatore, PreferenceCategory, che permette di raggruppare questi elementi, separandoli in base alla loro funzione logica.

Ready, steady, code!

Dopo l'infarinatura sulla natura del file preferences.xml, è finalmente giunto il momento di scrivere il codice per creare il menù di configurazione per la nostra applicazione. Per questo esempio creerò un semplice file composto da una checkbox e un editor di testo.
Nella cartella res/xml (che va creata se non presente) inseriamo il file preferences.xml così fatto:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android">

 <PreferenceCategory
   android:title="First PreferenceCategory">

  <CheckBoxPreference
    android:key="checkbox_preference"
    android:title="title checkbox preference"
    android:summary="summary of the checkbox preference" />
 </PreferenceCategory>

 <PreferenceCategory
   android:title="Second PreferenceCategory">

  <EditTextPreference
    android:key="edittext_preference"
    android:title="title edittext preference"
    android:summary="summary of the edittext preference"
    android:dialogTitle="dialog title edittext preference" />

 </PreferenceCategory>

</PreferenceScreen>


Ora possiamo creare il menù delle opzioni vero e proprio.
Aggiungiamo una nuova classe al progetto che si occuperà di visualizzare il menù appena creato, per funzionare correttamente deve estendere android.preference.PreferenceFragment. Nel metodo onCreate specifichiamo la creazione del contenuto in base al file res/xml/preferences.xml così:

package com.blogspot.virtualinsanity106.preferences.fragments;

import com.blogspot.virtualinsanity106.preferences.R; //NOT android.R

import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.util.Log;

public class PreferencesTest extends PreferenceFragment {
 private static final String TAG = "PreferencesTest";
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  //create the fragment content from preferences.xml
  addPreferencesFromResource(R.xml.preferences);
  Log.d(TAG, "Content created");
 }
}


Ora creiamo gli xml per le due Activity.
La prima è quella principale (MainActivity), che si occupa di caricare e visualizzare le
preferenze dell'utente e visualizzare il menù di decodifica su richiesta dell'utente.
La seconda (SetPreferencesActivity) invece visualizza il fragment e torna all'Activity
principale.

Cominciamo dal file res/layout/main.xml che contiene 2 TextView per visualizzare i dati :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 <!-- this shows the edittext_preference preference -->
 <TextView
  android:id="@+id/textview_edittext"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text=""
  android:textAppearance="?android:attr/textAppearanceLarge" />
 <!-- this shows the checkbox_preference preference -->
 <TextView
  android:id="@+id/textview_checkbox"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="" />
 <!-- this shows the SetPreferencesActivity activity-->
 <Button
  android:id="@+id/button_edit"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/button_edit_label"
  android:onClick="onEditClick"/><!-- function to show the edit activity -->

</LinearLayout>


Ora creiamo il file res/layout/setpreferences.xml, in modo da visualizzare il fragment e un bottone per tornare a MainActivity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 <!-- this is the preferences fragment -->
 <fragment
  android:id="@+id/fragment_preferences"
  android:name="com.blogspot.virtualinsanity106.preferences.fragments.PreferencesTest"
  android:layout_width="match_parent"
  android:layout_height="wrap_content" />
 <!-- this is the "Back" button -->
 <Button
  android:id="@+id/button_back"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:text="@string/button_back_label"
  android:onClick="onBackClick"/><!-- function to come back to the main activity -->

</LinearLayout>

Ora passiamo alla creazione della parte Java delle activity. SetPreferencesActivity si occuperà semplicemente di creare il layout definito in setpreferences.xml alla creazione e di terminare l'activity al click del bottone, così:

package com.blogspot.virtualinsanity106.preferences;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

public class SetPreferencesActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.setpreferences);
 }
 public void onBackClick(View v){
  setResult(RESULT_OK);
  finish();
 }
}

Mentre MainActivity si occupa di creare, al load,  il layout definito in main.xml e di caricare i dati salvati dall'utente. Quando si clicca sul bottone, l'applicazione visualizzerà l'activity SetPreferencesActivity e, terminata quest'ultima, ricaricherà i dati salvati dall'utente; così:

package com.blogspot.virtualinsanity106.preferences;

import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;

public class MainActivity extends Activity {
 private static final String TAG = "MainActivity";
 private TextView txtDisplayEditText;
 private TextView txtDisplayCheck;
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  loadPreferences(); //when the preferencesactivity ends, reload preferences when properties activity close
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);//set the content from main.xml
 txtDisplayEditText = (TextView) findViewById(R.id.textview_edittext);
  txtDisplayCheck = (TextView) findViewById(R.id.textview_checkbox);
  loadPreferences();//load the edited preferences
 }
 public void onEditClick(View v){
  //open the properties activity
  Log.d(TAG, "Start edit");
  Intent intent = new Intent();
  intent.setClass(MainActivity.this, SetPreferencesActivity.class);
  startActivityForResult(intent, 0);
 }
 private void loadPreferences(){
  SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); //load the preferences
  txtDisplayEditText.setText(sharedPreferences.getString("edittext_preference", getString(R.string.edittext_default_text))); //by default show the edittext_default_text string
  boolean isCheckboxSelected = sharedPreferences.getBoolean("checkbox_preference", false);//by default the checkbox isn't selected
  if(isCheckboxSelected)//if the checkbox is selected, show the "checkbox_true" string, otherwise show the "checkbox_false" string
   txtDisplayCheck.setText(getString(R.string.checkbox_true));
  else
   txtDisplayCheck.setText(getString(R.string.checkbox_false));
 }
}

Per finire, aggiungiamo SetPreferencesActivity nel AndroidManifest.xml con:
<activity android:name="SetPreferencesActivity"></activity>

Conclusione

In questo post abbiamo visto come visualizzare, salvare e recuperare le impostazioni dell'utente grazie all'API Preferences. Essendo un API integrata nel sistema non ha bisogno di aggiungere delle librerie esterne. Inoltre, aggiungendo il menù di configurazione tramite un xml di layout, è possibile inserire alcuni elementi estranei alla configurazione (nell'esempio il pulsante Back) senza dover utilizzare escamotage per simularne il funzionamento. Alcuni file, per ragioni di spazio, sono stati omessi; il progetto, completo di tutti i sorgenti è disponibile qui

Nessun commento:

Posta un commento