terça-feira, 4 de março de 2014

Android - Além dos 50 Projetos

Pode-se dizer que meu livro de maior sucesso chama-se "Android em 50 Projetos", este livro ocupa o primeiro da lista dos mais vendidos do site da VisualBooks a um bom tempo.


Gosto muito desse livro principalmente por ser muito prático, a teoria foi embutida dentro dos projetos, assim os leitores podem aprender criando. Obviamente que o período de criação não para então vou aproveitar este blog para dar continuação a mais alguns projetos e tentar passar mais algumas teorias que não foram vistas no livro.

Não, você não precisa comprar o livro para usar estes projetos. Basta ir no meu site e na seção do Curso Android e baixar gratuitamente os 8 tutoriais introdutórios.

Ficha do Projeto 51

Nome do Projeto: Faltam
Plataforma: Android 2.3.3 (Honeycomb)
Nome do Pacote: projeto.livro.faltam
Nome da Atividade: MainActivity
Versão mínima do SDK: 10
Uma grande preocupação que sempre tive foi de me lembrar de datas importantes, por exemplo, Quanto falta para o meu aniversário de casamento? Quanto falta para o aniversário da minha esposa? E do meu filho? Outras também gostaria de saber, quanto falta para o Natal por exemplo. Mas também posso usá-lo para pagar as contas mensais. Então a ideia deste aplicativo é inserir uma descrição e sua pseudo data, com DD ou DD/MM e com base na data atual ser informado quantos dias faltam para chegar aquela pseudo data.

Camada de Visão

Vamos começar trabalhando com as Strings que iremos utilizar, então modifique o arquivo Strings.xml contido na pasta res/values:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Faltam</string>
    <string name="action_settings">Faltam</string>
    <string name="lbDescricao">Descrição do evento:</string>
    <string name="htDescricao">Informe um descritivo do evento</string>
    <string name="lbDia">Dia ou Dia/Mês:</string>
    <string name="htDia">Informe DD ou DDMM</string>
    <string name="btGuardar">Guardar</string>
    <string name="btEliminar">Eliminar</string>
</resources>
Próximo passo é acertarmos o layout principal, para isso altere o arquivo content_main.xml contido na pasta res/layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/lbDescricao" />
    <EditText
        android:id="@+id/descricao"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/htDescricao" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/lbDia" />
    <EditText
        android:id="@+id/dia"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"
        android:hint="@string/htDia" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/guardar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/btGuardar" />
        <Button
            android:id="@+id/eliminar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/btEliminar" />
    </LinearLayout>
    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
Na primeira parte teremos dois campos para a entrada dos dados (descrição e dia), os botões separam esta primeira parte da listagem contendo os eventos já cadastrados.

Classe de Registro

Sempre que trabalhamos com listas é ideal criar uma classe que representa um registro desta, e isso facilitará nosso trabalho posterior de armazenar este registro. No pacote projeto.livro.faltam crie uma nova classe chamada Registro com a seguinte codificação:
public class Registro implements Serializable {

  private static final long serialVersionUID = 1L;
  private final String descricao;
  private final String dia;

  public Registro(final String descricao, final String dia) {
    this.descricao = descricao;
    this.dia = dia;
  }

  @Override
  public String toString() {
    return descricao + " | " + dia;
  }
}
Esta classe implementa a interface Serializable pois seus objetos serão armazenados. Nesta temos dois campos descrição e dia do tipo String. Para evitar a criação de métodos set/get usamos o construtor da classe e modificamos o método toString (que em breve receberá novos códigos).

Atividade Principal

Na classe MainActivity.java deixe-a com a seguinte codificação:
public class MainActivity extends ListActivity {

  private EditText edDescricao;
  private EditText edDia;
  private List lista = null;

  private void carregarDados() {
    lista = new ArrayList();
    ObjectInputStream ois = null;
    try {
      ois = new ObjectInputStream(openFileInput("dias.reg"));
      Registro reg;
      do {
        reg = (Registro)ois.readObject();
        lista.add(reg);
      } while (true);
    } catch (EOFException e) {
    } catch (Exception e) {
      Log.e("Faltam", "Erro Leitura: " + e.getMessage());
    } finally {
      try {
        ois.close();
      } catch (Exception e) {
        Log.e("Faltam", "Erro ao Fechar Arquivo: " + e.getMessage());
      }
    }
    if (lista != null) {
      ArrayAdapter adaptador =
          new ArrayAdapter(this, 
          android.R.layout.simple_expandable_list_item_1, lista);
      setListAdapter(adaptador);
    }
  }

  private void guardarRegistro() {
    Registro reg = new Registro(
      edDescricao.getText().toString(), edDia.getText().toString());
    ObjectOutputStream oos = null;
    try {
      oos = new ObjectOutputStream(
        openFileOutput("dias.reg", Context.MODE_PRIVATE));
      for (Registro regs : lista) {
        oos.writeObject(regs);
        oos.flush();
      }
      oos.writeObject(reg);
      oos.flush();
    } catch (Exception e) {
      Log.e("Faltam", "Erro Gravação: " + e.getMessage());
    } finally {
      try {
        oos.close();
      } catch (IOException e) {
        Log.e("Faltam", "Erro ao Fechar Arquivo: " + e.getMessage());
      }
    }
    edDescricao.setText("");
    edDia.setText("");
    edDescricao.requestFocus();
    carregarDados();
  }

  @Override
  protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    edDescricao = (EditText)findViewById(R.id.descricao);
    edDia = (EditText)findViewById(R.id.dia);
    findViewById(R.id.guardar).setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(final View v) {
            guardarRegistro();
          }
        });
    carregarDados();
  }
}
Como o layout desta classe possui uma lista, então passa a ser herança de ListActivity. O método carregarDados obtém os dados a partir de um arquivo texto que foi armazenado com os objetos de registro, e são lidos através de um ObjectInputStream, que são adicionados em uma Lista desses objetos, o último passo é criar um ArrayAdapter para carregar essa lista na tela. O método guardarRegistro obtém os dados que foram digitados nos campos EditText e os armazena (como objeto do tipo registro) no arquivo texto.

Existem alguns problemas quanto a leitura e a armazenagem de objetos. Quanto a leitura é impossível saber quando terminou, portanto repare que o laço de leitura só termina quando acontece um EOFException. Já na gravação o certo seria usar um tipo Context.MODE_APPEND no método openFileInput só que isso simplesmente não funciona, resultado, toda vez devemos gravar os dados antigos e o novo registro.

No método onCreate amarramos nossos EditText de tela com dois objetos da classe, armamos o evento onClick para o botão guardar um novo registro e carregamos os dados já armazenados.

E a primeira parte do nosso projeto está pronta o que resultará na seguinte tela:


Ainda está meio esquisito a listagem que não mostra os dias faltantes para o evento e também não é possível eliminar qualquer registro. Em breve, veremos como realizar essas atividades.

Obrigado e até a próxima
Fernando Anselmo

0 comentários:

Postar um comentário