Livello di difficoltà: medioVersione SDK utilizzata: >1.5Link al file compresso del progetto eclipse: file in allegatoIl
pattern architetturale MVC è uno dei pattern più diffusi nella programmazione object oriented e nello sviluppo di interfacce grafiche.
L'
MVC aumenta la coesione del nostro sistema software, in quanto la responsabilità di ogni classe viene mirata a compiti specifici.
Abbiamo un
Modello dati, che come da nome, gestisce l'accesso ai dati in lettura e scrittura.
Abbiamo una
View, la nostra interfaccia grafica, in android non è altro che la nostra Activity con le Views 'linkate' al file XML
Abbiamo il
Controller, ovvero tutto quello che riguarda la logica che avviene dopo l'interazione con l'utente e va a modificare lo stato degli altri due componenti.
Vediamo un esempio di utilizzo di questo pattern in android:
Creiamo un semplice layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:text="start service"
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button
android:text="stop service"
android:id="@+id/stopButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<TextView
android:id="@+id/myDataTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Premi 'start service' per iniziare"
android:inputType="textMultiLine" />
</LinearLayout>Modelpublic class MyDataModel extends Observable {
private String myData;
static MyDataModel singleInstance;
// Singleton design pattern
// usando questo pattern, siamo sicuri di avere
// una sola istanza del nostro modello dati
// e lo rendiamo reperibile agli utilizzatori tramite un metodo che ritorna la sua istanza
public static MyDataModel getInstance(){
if(singleInstance==null){
singleInstance=new MyDataModel();
}
return singleInstance;
}
public String getMyData() {
return myData;
}
public void setMyData(String myData) {
this.myData = myData;
setChanged();
notifyObservers();
// ogni volta che i dati cambiano, gli osservanti vengono informati
// il metodo update verrà chiamato su di essi
}
}Viewpublic class MvcDemo extends Activity implements Observer {
Button startButton;
Button stopButton;
TextView myDataTv;
MyDataModel dataModel;
Intent service;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setUpViews();
dataModel=MyDataModel.getInstance();
dataModel.addObserver(this); // aggiungiamo la nostra "View" come osservatore del modello dati
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//vogliamo complicarci la vita,
//invece di effettuare la modifica sui dati del modello da qui
//facciamo eseguire questa modifica da un servizio
service=new Intent(getApplicationContext(), MyService.class);
startService(service);
}
});
stopButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(service!=null)
stopService(service); //si commenta da solo...
}
});
}
private void setUpViews() {
startButton=(Button)findViewById(R.id.startButton);
stopButton=(Button)findViewById(R.id.stopButton);
myDataTv=(TextView)findViewById(R.id.myDataTextView);
}
@Override
public void update(Observable observable, Object data) { //interfaccia observer
if(observable instanceof MyDataModel){
// in quanto potremmo avere piu modelli dati
// verifichiamo su quale modello è avvenuto un cambiamento dei dati
// prima di effettuare il cast
MyDataModel m=(MyDataModel)observable;
myDataTv.append(m.getMyData());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(service!=null)
stopService(service); // quando la nostra activity cessa di esistere, fermiamo il servizio
}
}Controllerpublic class MyService extends Service {
MyDataModel dataModel=MyDataModel.getInstance();
Timer timer=new Timer();
Handler handler;
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
//potremmo chiamare dataModel.setMyData("\n Hello from Service");
//direttamente qui e sarebbe tutto apposto, ma vogliamo usare un TimerTask.
//I timertask implementano l'interfaccia Runnable
//quindi li possiamo classificare come delle Thread.
//come sappiamo per poter agire sulla UI da una Thread, occorre utilizzare degli Handler
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dataModel.setMyData("\n Hello from Service");
//modifica modello dati
}
};
timer.schedule(new TimerTask() {
@Override
public void run() {
Log.v("myService", "tic");
handler.sendEmptyMessage(0); //usiamo l'handler
}
},
0,
1000);
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel(); // una volta che il servizio viene a meno. 'puliamo' il timer
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Ovviamente per usare un servizio, il manifest va modificato di conseguenza.
Ad ogni modo, trovate il tutto in un progetto eclipse allegato.
Questo è tutto, spero che il tutorial sia di vostro gradimento

Saluti.
Qlimax