Início > Padrão de Projeto > APLICANDO MVC/CAMADAS EM UM PROJETO ANDROID – PARTE FINAL 2

APLICANDO MVC/CAMADAS EM UM PROJETO ANDROID – PARTE FINAL 2

         Olá pessoal, desculpa pela demora da segunda parte do tutorial Aplicando MVC/Camadas em um projeto Android. Tive diversos problemas pessoais e agora já estou bem melhor obrigado :D. Chega de conversa e vamos ao que interessa. Nesta segunda parte criei um projeto onde o intuito é demonstrar a implementação do MVC/Camadas em um projeto Android. Não irei explicar todo o funcionamento da aplicação, pois o intuito é apenas de demonstrar o fluxo da interação entre as camadas.Vale lembrar que existem diversas maneiras de se implementar o padrão MVC em um projeto.

Falando do projeto

         O aplicativo criado para demonstrar a implementação do padrão MVC é um CRUD (Create, Read, Update e Delete) básico para cadastrar um Carro em uma base de dados utilizando a api do Android SQLiteDataBase como ORM (object –relational  mapping). Como o intuito nesse post é de demonstrar uma estrutura MVC/Camada no projeto.

Basicamente a estrutura de pacote foi definida em camdas entre View, Negócio e Persistência. Onde, dentro do pacote de View ficam as Telas e Activitys, dentro do pacote de Negócio ficam as classes Model e suas Entidades e dentro de Persistência ficam as classes responsáveis por persistir dados e classes responsáveis por criar a estrutura da base de dados.

Tela  (View)

         A criação de tela no Android pode ser feita através de arquivo XML ou de classe Java. Por padrão, o recomendado para criação de tela é que utilize arquivo XML para criação de tela e classe Java apenas para criar telas dinâmicas. No MVC, as telas se encaixam como View . Pois as telas têm a finalidade de exibir conteúdo para o usuário. Abaixo mostro um exemplo de tela que seria a tela principal da aplicação.

 


<?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">
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="@string/hello" />

	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="@string/nomeCarro" />

	<EditText android:layout_height="wrap_content"
		android:layout_width="fill_parent"
		android:id="@+id/editNome" />

	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="@string/placaCarro" />

	<EditText android:layout_height="wrap_content"
		android:layout_width="fill_parent"
		android:id="@+id/editPlaca" />

	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="@string/modeloCarro" />

	<EditText android:layout_height="wrap_content"
		android:layout_width="fill_parent"
		android:id="@+id/editModelo" />

	<!-- Criação de um LinearLayout para o agrupamento de botões -->

	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="horizontal" android:layout_width="fill_parent"
		android:layout_height="fill_parent" android:layout_marginTop="160dip">

		<Button android:text="@string/enviarCarro" android:id="@+id/buttonEnviar"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"/>

		<Button android:text="@string/buscarCarro" android:id="@+id/buttonBuscar"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"/>

		<Button android:text="@string/excluirCarro" android:id="@+id/buttonExcluir"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"/>

	</LinearLayout>

</LinearLayout>

Controller (View)

As Activities da aplicação são responsáveis por realizar a comunicação da tela com o sistema, bem como da classe Model com a sua tela correspondente. Abaixo mostro a Activity principal para um maior entendimento sobre o assunto.

package com.br.douglasalipio.view.controlador;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.br.douglasalipio.R;
import com.br.douglasalipio.exception.CampoObrigatorioCarroException;
import com.br.douglasalipio.negocio.entidade.Carro;
import com.br.douglasalipio.negocio.model.CarroModel;
import com.br.douglasalipio.persistencia.repositorio.DatabaseCreate;

/**
 *
 * @author douglas
 *
 */
public class MainController extends Activity implements OnClickListener {

	private Button enviar;
	private Button buscar;
	private Button excluir;

	private EditText nome;
	private EditText placa;
	private EditText modelo;

	private CarroModel carroNegocio;
	private DatabaseCreate dbCreate;
	private Carro carro;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main_view);

		carroNegocio = new CarroModel(this.getApplication());
		dbCreate = new DatabaseCreate(this);

		nome = (EditText) findViewById(R.id.editNome);
		placa = (EditText) findViewById(R.id.editPlaca);
		modelo = (EditText) findViewById(R.id.editModelo);

		enviar = (Button) findViewById(R.id.buttonEnviar);
		buscar = (Button) findViewById(R.id.buttonBuscar);
		excluir = (Button) findViewById(R.id.buttonExcluir);

		enviar.setOnClickListener(this);
		buscar.setOnClickListener(this);
		excluir.setOnClickListener(this);

	}

	@Override
	public void onClick(View v) {

		switch (v.getId()) {

		case R.id.buttonBuscar:

			abrirTelaBusca();
			break;

		case R.id.buttonEnviar:

			carro = recuperarInformacaoCarro();
			enviarCarro();
			limparCampos();

			break;

		case R.id.buttonExcluir:

			abrirTelaExclusao();
			break;
		}

	}

	/**
	 * Envia o objeto carro para ser validado.
	 *
	 */
	private void enviarCarro() {

		try {

			carroNegocio.tratarInsercaoCarro(carro);

		} catch (CampoObrigatorioCarroException e) {
			Toast.makeText(this, R.string.nomeObrigatorio, Toast.LENGTH_LONG)
					.show();

		}
	}

	/**
	 * Limpa os campos da tela de Carro.
	 */
	private void limparCampos() {

		Toast.makeText(getApplication(), R.string.sucesso, Toast.LENGTH_LONG)
				.show();

		nome.setText("");
		modelo.setText("");
		placa.setText("");

	}

	/**
	 * Recupera informações do carro e preenche o objeto.
	 *
	 * @return
	 */
	private Carro recuperarInformacaoCarro() {

		Carro carro = new Carro(nome.getText().toString(), placa.getText()
				.toString(), modelo.getText().toString());

		return carro;

	}

	/**
	 * Abre a tela de busca.
	 */
	private void abrirTelaBusca() {

		Intent it = new Intent(this, BuscarCarroController.class);
		startActivity(it);

	}

	/**
	 * Abre a tela de exclusão.
	 */
	private void abrirTelaExclusao() {

		Intent it = new Intent(this, ExcluirCarroController.class);
		startActivity(it);

	}
}

Model (Negócio)

As classes Model representam o estado de sua aplicação, ou seja, são elas que tratarão a regra de negócio de seu domínio. Abaixo mostro a classe CarroModel que representa o modelo da aplicação exemplo deste tutorial.


package com.br.douglasalipio.negocio.model;

import com.br.douglasalipio.R;
import com.br.douglasalipio.exception.CampoObrigatorioCarroException;
import com.br.douglasalipio.exception.GenericoException;
import com.br.douglasalipio.exception.IdInvalidoException;
import com.br.douglasalipio.negocio.entidade.Carro;
import com.br.douglasalipio.persistencia.CarroPersistencia;

import android.content.Context;

/**
 *
 * @author douglas
 *
 */
public class CarroModel {

	private Context context;
	private CarroPersistencia carroPersistencia;

	public CarroModel(Context context) {

		this.context = context;
	}

	public void tratarInsercaoCarro(Carro carro)
			throws CampoObrigatorioCarroException {

		if (carro.getNome() == null) {

			throw new CampoObrigatorioCarroException(R.string.nomeObrigatorio);

		} else {

			carroPersistencia = CarroPersistencia.getInstance(context);
			carroPersistencia.inserirCarro(carro);

		}

	}

	public Carro tratarBuscaCarro(String nomeCarro) throws IdInvalidoException {

		if (nomeCarro != null) {

			carroPersistencia = CarroPersistencia.getInstance(context);
			return carroPersistencia.buscarCarro(nomeCarro);

		} else {

			throw new IdInvalidoException("Id inválido");
		}

	}

	public void tratarAtualizacaoCarro(Carro carro) throws GenericoException {

		if (carro != null) {

			carroPersistencia = CarroPersistencia.getInstance(context);
			carroPersistencia.atualizarCarro(carro);

		} else {

			throw new GenericoException();
		}
	}

	public void tratarExclusaoCarro(String nomeCarro) throws GenericoException {

		if (nomeCarro != null) {
			carroPersistencia = CarroPersistencia.getInstance(context);
			carroPersistencia.deletarCarro(nomeCarro);
		} else {

			throw new GenericoException();
		}
	}

}

Persistência

A camada de persistência é responsável por persistir, por exemplo, dados em um diretório, arquivos ou banco de dados. Abaixo mostro a classe CarroPersistencia.java que é responsável por persistir dados em uma base de dados.


package com.br.douglasalipio.persistencia;

import com.br.douglasalipio.negocio.entidade.Carro;
import com.br.douglasalipio.persistencia.repositorio.CarroModelDB;
import com.br.douglasalipio.persistencia.repositorio.DatabaseCreate;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

/**
 *
 * @author douglas
 *
 */
public class CarroPersistencia {

	private Context context;
	private static CarroPersistencia instance;
	private static SQLiteDatabase db;

	public static CarroPersistencia getInstance(Context context) {
		if (instance == null) {
			synchronized (CarroPersistencia.class) {

				if (instance == null) {

					instance = new CarroPersistencia(context);

					db = context.openOrCreateDatabase(
							DatabaseCreate.TUTORIAL_DB, Context.MODE_PRIVATE,
							null);
				}
			}
		}
		return instance;
	}

	private CarroPersistencia(Context context) {

		this.context = context;

	}

	/**
	 * Persiste informações de carro.
	 *
	 * @param carro
	 */
	public void inserirCarro(Carro carro) {

		ContentValues value = new ContentValues();
		value.put(CarroModelDB.NOME_CARRO, carro.getNome());
		value.put(CarroModelDB.PLACA_CARRO, carro.getPlaca());
		value.put(CarroModelDB.MODELO_CARRO, carro.getModelo());
		db.insertOrThrow(CarroModelDB.CARRO, "", value);

	}

	/**
	 * Atualiza um carro.
	 *
	 * @param carro
	 */
	public void atualizarCarro(Carro carro) {

		Long idCarro = carro.getId();
		ContentValues values = new ContentValues();
		String[] whereArgs = new String[] { idCarro.toString() };
		String where = CarroModelDB.ID_CARRO + "=?";

		values.put(CarroModelDB.MODELO_CARRO, carro.getModelo());
		values.put(CarroModelDB.NOME_CARRO, carro.getNome());
		values.put(CarroModelDB.PLACA_CARRO, carro.getPlaca());
		db.update(CarroModelDB.CARRO, values, where, whereArgs);

	}

	/**
	 * Deleta um carro
	 *
	 * @param idCarro
	 */
	public void deletarCarro(String nomeCarro) {

		db.delete(CarroModelDB.CARRO,
				CarroModelDB.NOME_CARRO + "=" + "'"+nomeCarro+"'", null);

	}

	/**
	 * Busca e recupera o carro pesquisado.
	 *
	 * @param nomeCarro
	 * @return
	 */

	public Carro buscarCarro(String nomeCarro) {

		Cursor cursor = db.query(CarroModelDB.CARRO, CarroModelDB.COLUNAS,
				CarroModelDB.NOME_CARRO + "='" + nomeCarro + "'", null, null,
				null, null);

		Carro carro = new Carro();

		if (cursor.moveToFirst()) {

			carro.setId(cursor.getInt(cursor
					.getColumnIndexOrThrow(CarroModelDB.ID_CARRO)));

			carro.setNome(cursor.getString(cursor
					.getColumnIndexOrThrow(CarroModelDB.NOME_CARRO)));

			carro.setModelo(cursor.getString(cursor
					.getColumnIndexOrThrow(CarroModelDB.MODELO_CARRO)));

			carro.setPlaca(cursor.getString(cursor
					.getColumnIndexOrThrow(CarroModelDB.PLACA_CARRO)));

		}

		return carro;
	}

}

Interação entre as camadas no projeto

A interação entre as camadas de View, Negócio e Persistência fica basicamente entre, Main.xml, MainController.java, CarroModel.java e CarroPersistencia.java. Abaixo, demonstro apenas o ponto de interação entre essas classes (camadas).

MainController – tem a responsabilidade de instanciar os componentes de sua View, tratar regra de View (nesse caso seria a tela main.xml) e se comunicar com o seu Model responsável.


  private CarroModel carroNegocio;

           public void onCreate(Bundle savedInstanceState) {
		   super.onCreate(savedInstanceState);

                carroNegocio = new CarroModel(this.getApplication());

           }

	@Override
	public void onClick(View v) {

		switch (v.getId()) {

		case R.id.buttonEnviar:

			carro = recuperarInformacaoCarro();
			enviarCarro();
			limparCampos();

			break;

	}
        private void enviarCarro() {

		try {

			carroNegocio.tratarInsercaoCarro(carro);

		} catch (CampoObrigatorioCarroException e) {
			Toast.makeText(this, R.string.nomeObrigatorio, Toast.LENGTH_LONG)
					.show();

		}
	}

Pontos importantes do trecho de código acima:

Ponto 1
É a criação do atributo que se comunica com o seu Model responsável

 private CarroModel carroNegocio; 

<strong>Ponto 2</strong>
É inicializado no momento em que a tela não está disponível para o usuário neste caso, dentro do método onCreate().

 carroNegocio = new CarroModel(this.getApplication()); 

Ponto 3
É a chamada do método de inserção do botão criado em main.xml

CarroModel – Tem a responsabilidade de receber o contexto da aplicação e de tratar a regra de negócio da tela Carro.

Ponto 4
Cria o atributo para ser inicializado através do construtor. Com o Contexto na camada de Model, é possível passar o mesmo para a camada de persistência e realizar operações que necessitam dele, como por exemplo, openOrCreateDatabase que tem a função de criar uma base de dado.

private Context context;

		public CarroModel(Context context) {

			this.context = context;
		}

Ponto 5
Cria um atributo que recebe uma instância singleton de CarroPersistencia e cria um método que trata a inserção de um carro na base de dados.


private CarroPersistencia carroPersistencia;

		public void tratarInsercaoCarro(Carro carro)
			throws CampoObrigatorioCarroException {

		if (carro.getNome() == null) {

			throw new CampoObrigatorioCarroException(R.string.nomeObrigatorio);

		} else {

			carroPersistencia = CarroPersistencia.getInstance(context);
			carroPersistencia.inserirCarro(carro);

		}

	}
	enviarCarro();

Ponto 6
É a chamada ao método que trata a regra de negócio desta view (main.xml).
carroNegocio.tratarInsercaoCarro(carro);

CarroPersistencia – Tem a responsabilidade de persistir dados e de abrir a base de dados.

Ponto 7
Passa como parâmetro no construtor de CarroPersistencia o contexto que serve para abrir ou criar a base de dados.


public static CarroPersistencia getInstance(Context context) {
		if (instance == null) {
			synchronized (CarroPersistencia.class) {

				if (instance == null) {

					instance = new CarroPersistencia(context);

					db = context.openOrCreateDatabase(
							DatabaseCreate.TUTORIAL_DB, Context.MODE_PRIVATE,
							null);
				}
			}
		}
		return instance;
	}

Ponto 8
Cria um método que faz uma inserção de carro na base de dados.


public void inserirCarro(Carro carro) {

		ContentValues value = new ContentValues();
		value.put(CarroModelDB.NOME_CARRO, carro.getNome());
		value.put(CarroModelDB.PLACA_CARRO, carro.getPlaca());
		value.put(CarroModelDB.MODELO_CARRO, carro.getModelo());
		db.insertOrThrow(CarroModelDB.CARRO, "", value);

	}

O projeto esta com um código bem simples e pode ser baixado aqui

Anúncios
Categorias:Padrão de Projeto
  1. le
    outubro 7, 2013 às 11:48 pm

    Estou baixando o exemplo, muito obrigado e parabéns!
    Continue assim!

  2. David
    dezembro 31, 2013 às 9:21 am

    eu te amo! i love you…. loveeee youuu….. only you are my first and last love….. Looooveee

    cara, vlw!! cantei ate uma musica para tu! kkkkk, é o cafe, noite sem dormir!

  3. David
    janeiro 13, 2014 às 5:49 am

    Ola, qual versao eu devo usar ? eu estava tentando agora, rodar, mas nao roda nas minhas maquinas emuladas! qual android voce usou ?
    ha tambem erros nos XMLs (atualizar, o adt aqui, acusou lienar layout, erro android apk, pasta res la… e no manifest, erro de activity repetida, testa ai! Att

  4. toni
    maio 6, 2014 às 3:43 pm

    Olá !!! adorei o tutorial, mas tive dificuldades em construir uma classe para foto, com adicionar foto nesse cadastro.
    Desde já agradeço a atenção

  5. Daylon
    setembro 4, 2014 às 6:43 pm

    Como faço para criar uma nova tabela moto por exemplo?

    • setembro 4, 2014 às 7:57 pm

      Cria uma classe abstrata chamada Automovel e faz com que a sua classe Moto implemente-a.

  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: