Hoje em dia a demanda de desenvolvimento de aplicativos móveis é muito alta. Para ser competitivo, um aplicativo móvel deve ser eficaz em termos de custos e ser de boa qualidade.

A escolha da arquitetura é importante para garantir a qualidade da aplicação a longo tempo e para reduzir o tempo de desenvolvimento.

O desenvolvimento iOS é baseado no Model-View-Controller e é bem estruturado. O sistema Android não requer qualquer modelo: a escolha da arquitetura e a qualidade da aplicação dependem muito da experiência do desenvolvedor.

Soluções heterogêneas desaceleram o desenvolvedor, enquanto o padrão de design conhecido não só poderia aumentar o tempo de desenvolvimento, mas melhorar a capacidade de manutenção, extensibilidade e o desempenho da aplicação.

MVC (Model-View-Controller) é um padrão de projeto de software que separa a interface do usuário (View) e das regras de negócio e dados (Model) usando um mediador (Controller) para conectar o modelo à view.

O principal benefício do MVC para nós é a separação de interesses. Cada parte do MVC cuida de seu próprio trabalho: a view cuida da interface com o usuário, o modelo se encarrega dos dados, e o controlador envia mensagens entre os dois.

O controlador fornece os dados do modelo para a view se ligar a interface do usuário. Quaisquer alterações ao controlador são transparentes para a view e as mudanças de interface do usuário não afetarão a lógica de negócios e vice-versa.

Os padrões de design ajudam a impor uma estrutura sobre os desenvolvedores para que o código se torne mais controlado e menos propenso a cair em desuso. A separação do MVC de interesses torna muito mais fácil para adicionar unidades de testes.

O Android já utiliza um padrão MVC com os arquivos XML agindo como a view. Contudo, isto não nos fornece quaisquer possibilidades reais de separação de interesses.

Para demonstrar o MVC (Model-View-Controller) framework para Android, criaremos um exemplo de tela que contém o logo da DEVMEDIA, conforme mostrado na Figura 1, e outra tela que contém um campo para digitar determinada tarefa a realizar e um botão de Nova Tarefa. Ao pressionar o botão, o valor da tarefa será incluído no banco de dados e na lista de tarefas a realizar. Ao selecionar algum item da lista, o mesmo será excluído do banco de dados, conforme mostrado na Figura 2.

Android MVC: Criando um Framework Model-View-Controller para Android

Figura 1. Tela Splash

Android MVC: Criando um Framework Model-View-Controller para Android

Figura 2. Tela Principal

A seguir, podemos visualizar a classe que atua como Model da aplicação, conforme mostrado na Listagem 1.

Nota: O Android tem integração com o SQLite, um leve e poderoso banco de dados, permitindo que você utilize banco de dados normalmente e sua aplicação. Um banco de dados é visível somente à aplicação que o criou. A classe SQLiteHelper encapsula toda a lógica de criação de um banco. Os métodos onCreate e onUpgrade são chamados automaticamente pelo Android quando o banco precisa ser criado pela primeira vez ou ao ser atualizado devido a uma nova versão.

Listagem 1. mvcModel.java


  package com.devmedia.mvc;
   
  import android.content.ContentValues;
  import android.content.Context;
  import android.database.Cursor;
  import android.database.sqlite.SQLiteDatabase;
  import android.database.sqlite.SQLiteOpenHelper;
  import android.util.Log;
   
  final class mvcModel
  {
      private static final String DB_NAME = "tarefas_db";
      private static final String TABLE_NAME = "tarefa";
      private static final int DB_VERSION = 1;
      private static final String DB_CREATE_QUERY = "CREATE TABLE " +
        mvcModel.TABLE_NAME + " (id integer primary key autoincrement, 
        titulo text not null);";
   
      private final SQLiteDatabase database;
      
      private final SQLiteOpenHelper helper;
   
      public mvcModel(final Context ctx)
      {
          this.helper = new SQLiteOpenHelper(ctx, mvcModel.DB_NAME,
           null, mvcModel.DB_VERSION)
          {
              @Override
              public void onCreate(final SQLiteDatabase db)
              {
                  db.execSQL(mvcModel.DB_CREATE_QUERY);
              }
   
              @Override
              public void onUpgrade(final SQLiteDatabase db, 
               final int oldVersion, final int newVersion)
              {
                  db.execSQL("DROP TABLE IF EXISTS " + mvcModel.TABLE_NAME);
                  this.onCreate(db);
              }
          };
   
          this.database = this.helper.getWritableDatabase();
      }
   
      public void addTarefa(ContentValues data)
      {
          this.database.insert(mvcModel.TABLE_NAME, null, data);
      }
   
      public void deleteTarefa(final String field_params)
      {
          this.database.delete(mvcModel.TABLE_NAME, field_params, null);
      }
   
      public Cursor loadAllTarefas()
      {
          Log.d(mvcView.APP_TAG, "loadAllTarefas()");
   
          final Cursor c = this.database.query(mvcModel.TABLE_NAME, 
           new String[] { "titulo" }, null, null, null, null, null);
   
          return c;
      }
  }

A seguir podemos visualizar a classe que atua como View da aplicação, conforme mostrado na Listagem 2.

Listagem 2. mvcView.java


  import android.widget.TextView;
   
  import com.devmedia.mvc.R;
   
  public class mvcView extends Activity
  {
      public static final String APP_TAG = "com.devmedia.mvc";
   
      private ListView lvTarefa;
      private Button btNovaTarefa;
      private EditText etNovaTarefa;
   
      private mvcController controller;
   
      @Override
      public void onCreate(final Bundle bundle)
      {
          super.onCreate(bundle);
   
          this.setContentView(R.layout.ui_main);
   
          this.controller = new mvcController(this);
          
          this.lvTarefa = (ListView) this.findViewById(R.id.lvTarefa);
          this.btNovaTarefa = (Button) this.findViewById(R.id.btNovaTarefa);
          this.etNovaTarefa = (EditText) 
           this.findViewById(R.id.etNovaTarefa);
          
          this.btNovaTarefa.setOnClickListener(this.handleNovaTarefaEvent);
   
          this.populaTarefas();
      }
   
      private void populaTarefas()
      {
          final List<String> tarefas = this.controller.getTarefas();
   
          Log.d(mvcView.APP_TAG, String.format("%d tarefas encontradas ", 
                 tarefas.size()));
   
          this.lvTarefa.setAdapter(new ArrayAdapter<String>
          (this, android.R.layout.simple_list_item_1, 
            tarefas.toArray(new String[] {})));
   
          this.lvTarefa.setOnItemClickListener(new OnItemClickListener()
          {
              @Override
              public void onItemClick(final AdapterView<?> parent, 
               final View view, final int position, final long id)
              {
                  Log.d(mvcView.APP_TAG, String.format("tarefa id: %d 
                   e posição: %d", id, position));
   
                  final TextView v = (TextView) view;
                  
                  mvcView.this.controller.deleteTarefa
                   (v.getText().toString());
                  
                  
                  mvcView.this.populaTarefas();
              }
          });
      }
      
      private final OnClickListener handleNovaTarefaEvent = 
       new OnClickListener()
      {
          @Override
          public void onClick(final View view)
          {
              Log.d(APP_TAG, "botão nova tarefa acionado");
   
               mvcView.this.controller.addTarefa(mvcView.this
               .etNovaTarefa.getText().toString());
   
              mvcView.this.populaTarefas();
          }
      };
   
   
      @Override
      protected void onStart()
      {
          super.onStart();
      }
      
      @Override
      protected void onStop()
      {
          super.onStop();
      }
  }

O Controller liga a interface do usuário com os dados, mas também cria uma camada de separação entre o Model e a View. Esta interface entre as duas camadas fornece uma estrutura para o código expandir.

A seguir podemos visualizar a classe que atua como Controller da aplicação, conforme mostrado na Listagem 3.

Listagem 3. mvcController.java


  package com.devmedia.mvc;
   
  import android.content.ContentValues;
  import android.content.Context;
  import android.database.Cursor;
   
  import java.util.ArrayList;
  import java.util.List;
   
  public class mvcController
  {
      private mvcModel model;
      private List<String> tarefas;
   
      public mvcController(Context app_context)
      {
          tarefas = new ArrayList<String>();
          model = new mvcModel(app_context);
      }
   
      public void addTarefa(final String titulo)
      {
          final ContentValues data = new ContentValues();
          data.put("titulo", titulo);
          model.addTarefa(data);
      }
   
      public void deleteTarefa(final String titulo)
      {
          model.deleteTarefa("titulo='" + titulo + "'");
      }
   
      public void deleteTarefa(final long id)
      {
          model.deleteTarefa("id='" + id + "'");
      }
   
      public void deleteAllTarefa()
      {
          model.deleteTarefa(null);
      }
   
      public List<String> getTarefas()
      {
          Cursor c = model.loadAllTarefas();
          tarefas.clear();
   
          if (c != null)
          {
              c.moveToFirst();
   
              while (c.isAfterLast() == false)
              {
                  tarefas.add(c.getString(0));
                  c.moveToNext();
              }
              
              c.close();
          }
   
          return tarefas;
      }
  } 

Uma tela splash screen deve permanecer aberta por determinado tempo para que a aplicação consiga realizar algum processamento inicial. Enquanto isso, o usuário pode ficar observando uma imagem ou mensagem na tela.

A seguir podemos visualizar a classe que atua como tela Splash da aplicação, conforme mostrado na Listagem 4.

Listagem 4. mvcSplash.java


  package com.devmedia.mvc;
   
  import android.app.Activity;
  import android.os.Bundle;
  import android.content.Intent;
   
  public class mvcSplash extends Activity
  {
      public void onCreate(Bundle savedInstanceState)
      {
          super.onCreate(savedInstanceState);
   
          setContentView(R.layout.ui_splash);
          
          Thread timer = new Thread()
          {
              public void run()
              {
                  try
                  {
                      sleep(1000);
                  }
                  catch (InterruptedException e)
                  {
                      e.printStackTrace();
                  }
                  finally
                  {
                      Intent intent = new Intent
                       ("com.devmedia.mvc.mvcView");
                      startActivity(intent);
                  }
              }
          };
          
          timer.start();
      }
  }

O arquivo AndroidManifest.xml é a base de uma aplicação Android. Ele é obrigatório e deve ficar na pasta raiz do projeto, contendo todas as configurações necessárias para executar a aplicação.

A seguir podemos visualizar o arquivo AndroidManifest, conforme mostrado na Listagem 5.

Listagem 5. AndroidManifest.xml


  <?xml version="1.0" encoding="utf-8"?>
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.devmedia.mvc"
      android:versionCode="1"
      android:versionName="1.0" >
      <uses-sdk
          android:minSdkVersion="8"
          android:targetSdkVersion="19" />
      <application
          android:allowBackup="true"
          android:icon="@drawable/ic_launcher"
          android:label="@string/app_name"
          android:theme="@style/AppTheme" >
          <activity android:label="@string/app_name"
              android:name="com.devmedia.mvc.mvcView">
              <intent-filter>
                  <action android:name="com.devmedia.mvc.mvcView" />
                  <category android:name=
                     "android.intent.category.DEFAULT" />
              </intent-filter>
          </activity>
          <activity android:name=".mvcSplash">
              <intent-filter>
                  <action android:name="android.intent.action.MAIN"/>
                  <category android:name=
                   "android.intent.category.LAUNCHER"/>
              </intent-filter>
          </activity>
      </application>
   
  </manifest>

O Android é bastante flexível em relação à criação da interface gráfica e permite que a tela seja criada em XML ou diretamente pelo código-fonte utilizando a API Java. Separando a criação da tela em um arquivo XML, seu código fica mais limpo. A seguir, podemos visualizar os arquivos de layout de tela, conforme mostrado nas Listagens 6 e 7.

Listagem 6. ui_main.xml


  <?xml version="1.0" encoding="utf-8"?>
   
  <RelativeLayout xmlns:android=
    "http://schemas.android.com/apk/res/android"
      
      android:id="@+id/widget31"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" >
   
      <TableRow
          android:id="@+id/row"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_below="@+id/lvTarefa"
          android:orientation="horizontal" >
   
          <EditText
              android:id="@+id/etNovaTarefa"
              android:layout_width="200dp"
              android:layout_height="wrap_content"
              android:text=""
              android:textSize="18sp" >
          </EditText>
   
          <Button
              android:id="@+id/btNovaTarefa"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/add_button_name" >
          </Button>
      </TableRow>
   
      <ListView
          android:id="@+id/lvTarefa"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentTop="true" >
      </ListView>
   
  </RelativeLayout>

Listagem 7. ui_splash.xml


  <?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">
   
         <ImageView
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:id="@+id/placekitten"
              android:src="@drawable/splash"/>
  </LinearLayout>

O arquivo strings.xml contém as mensagens da aplicação para organizar os textos em um único arquivo centralizado, o que é uma boa prática de programação. Desta forma, podemos facilmente traduzir este arquivo para diversos idiomas e tornar nossa aplicação bastante internacionalizável. A seguir, podemos visualizar o arquivo strings.xml, conforme mostrado na Listagem 8.

Listagem 8: strings.xml


  <?xml version="1.0" encoding="utf-8"?>
  <resources>
   
      <string name="app_name">Criando um MVC(Model-View-Controller)   
         framework para Android</string>
      <string name="action_settings">Settings</string>
      <string name="add_button_name">Nova Tarefa</string>
      
  </resources>

Um dos problemas fundamentais com todos os tipos de software pode ser resumido no conceito de entropia, que sugere que o código ordenado naturalmente se torna desordenado ao longo do tempo. Ou em outras palavras, não importa o quão duro você tente, seu código irá gradualmente ir de um estado organizado para um estado desorganizado em que também é conhecido como altamente acoplado.

Até a próxima!

Um abraço.

Referências:

http://developer.android.com/guide/index.html

http://www.sqlite.org/