sexta-feira, 18 de abril de 2014

Projeto - Nunca é tarde para aprender

Após a conclusão do curso superior o caminho natural para qualquer estudante é a Pós-Graduação do tipo Latu Sensu (resumidamente, um curso de especialização). O problema é: Qual? Existem atualmente diversos cursos e nos mais diversos assuntos, e estou mencionando apenas dentro da sua área. Não sou diferente de ninguém e resolvi encarar uma pós e escolhi uma em Gestão Empresarial.

"Para o barco que quero descer! o que isso tem a ver com informática?" Foi a primeira pergunta que me fizeram, "já sei você vai abrir uma empresa?" essa foi a segunda. Não, não pretendo abrir nenhuma empresa e sim isso tem tudo a ver com informática.

Uma das matérias que estou fazendo chama-se: Ferramentas de Gestão Avançada, aqui travamos conhecimento sobre os diversos tipos de ferramental existente para o gerenciamento de equipes e controle da empresa, além disso, trata das análises para a escolha da ferramenta. "Fernando, desejo ser apenas um desenvolvedor, no máximo chegar a analista, onde isso iria me interessar?", para lhe responder, pensemos que deseja que sua empresa adquira um novo software que lhe ajudará muito a realizar seu trabalho (e provavelmente outras pessoas também), após uma análise técnica vai solicitar a ferramenta para seu chefe e ocorre o seguinte diálogo:

- Chefe, estava analisando essa ferramenta X e é excelente, (expõe suas razões técnicas).
- E qual o ganho? - seu chefe pergunta.
- Todo! - você exclama feliz.
- Todo qual? - seu chefe pergunta.
- Veja bem...

Nessa hora tem a certeza que não desejaria estar ali. Voltando a minha matéria de FGA, um dos assuntos que conhecemos e a realização de uma análise de ROI (Return On Investiment) sobre qualquer ferramenta para a tomada de decisão. Então o diálogo com seu chefe muda para:

- Chefe, estava analisando essa ferramenta X e é excelente, (expõe suas razões técnicas).
- E qual o ganho? - seu chefe pergunta.
- Ao considerarmos que o ganho inicial de produtividade é de X% a ferramenta se pagará em menos de Y anos e gerar uma lucratividade de R$ Z. Após um tempo iremos aumentar o percentual de produtividade, pois o pessoal estará mais treinado e isso representa...

Acho que a conversa muda um pouco e creio que seu chefe olhará com outros olhos na hora que solicitar um aumento. Observe que estou falando de uma única matéria de um curso que dura 1 ano e meio. Tenha em mente que nunca é tarde para aprender e completaria com "qualquer coisa", pense sempre fora da caixa pois existem vários benefícios até mesmo em um curso que "aparentemente" pode não ter nada a ver com suas funções.

Disponibilizei no meu site pessoal (na seção de documentos) uma planilha que criei para realizar análises diversas para empresas (baixe aqui).

Obrigado e até a próxima,
Fernando Anselmo





sexta-feira, 11 de abril de 2014

Conhecimento - Conhece o VOLP

Permita-me fazer uma simples pergunta: Qual o plural da palavra álcool?

a. Não existe
b. álcools
c. alcoóis
d. álcoois

Vamos lá, se marcou a letra C provavelmente consultou o Houaiss eletrônico que registra o plural da palavra álcool como alcoóis. Já se consultou o Michaelis ou Aurélio eletrônico foi direto na letra D. E aí? Quem está correto?

Antes de responder, em um vídeo da Porta dos Fundos sobre Tempo, bem no final um colega pergunta ao repórter: "Como você faz a previsão do tempo?" e prontamente responde: "Eu consulto em um site de tempo", e outro retruca, "Mas esse site que você consulta, como faz para saber a previsão do tempo?", e o repórter responde: "Provavelmente também consulta em um site de tempo", e quem perguntou combate: "Mas, tudo bem se o site consulta outro, deve existir um site central que todo mundo consulta e que deve realizar a previsão. É desse site que estou perguntando, como ele realiza a previsão do tempo?", e o repórter responde: "Hum... Isso eu não sei, só sei que eu consulto em um site de previsão do tempo".

Então vamos a uma pergunta: "Quem é o responsável pelas palavras na Língua Portuguesa? Pela Gramática, pelas regras e por tudo?", muito bem se respondeu ABL (Academia Brasileira de Letras), o que significa que os imortais não ficam apenas tomando chá e discutindo sobre suas imortalidades (se isso acontesse nunca teria uma cadeira vaga). Concluindo, dicionários, gramáticas e tudo o mais para serem criados consultam? Exatamente, a ABL, pois é de lá que partem todas as regras da nossa língua.

As palavras para o dicionário vem do VOLP, isso é, Vocabulário Ortográfico da Língua Portuguesa e atualmente se encontra disponível gratuitamente e eletronicamente no site da ABL e nele podemos conseguir encontrar qualquer palavra da nossa língua. E se a palavra não existir lá? Então simplesmente não existe na nossa língua. Tente, por exemplo, buscar a palavra "Printar", isso significa que na próxima vez escreva no e-mail para seu chefe "O documento se encontra impresso e a disposição desta gerência" (do verbo Imprimir).

Por fim, pesquise a palavra "Álcool" e como resultado teremos "álcool s.m.; pl. álcoois e alcoóis" isso significa que tanto as letras C e D estão corretas. Fica a dica, toda vez que tiver alguma dúvida sobre qualquer palavra da língua portuguesa acesse gratuitamente o VOLP, ou seja, beba direto na fonte.

Obrigado e até a próxima
Fernando Anselmo

sábado, 5 de abril de 2014

Projeto - Usando Mapas Mentais para suas redações

Acredito que para muita gente não é fácil escrever, como diria uma professora de português: defender uma ideia falando é muito mais simples do que escrevê-la no papel. Por quê isso acontece? Existem vários fatores entre eles a falta de leitura e a falta de organização das ideias.

Quanto ao primeiro fator é algo muito pessoal, não pense que a leitura diária do horóscopo irá ajudá-lo a sanar este problema e por mais interessante que possa ser a Bíblia também, não trará nenhum benefício a sua escrita. Do contrário, editoriais de jornais ou artigos nos quais são defendidas posições técnicas, podem lhe auxiliar na formação de uma opinião. Lembre-se que escrever é defender um ponto de vista no qual se acredita e deve-se construir argumentos sólidos para esta defesa e pouco importa qual lado se defende.

Para a organização das ideias, tenho por convicção que o Mapa Mental é uma ferramenta de grande auxílio na construção de um suporte ideal. Sabemos que qualquer redação possui três áreas: introdução, desenvolvimento e conclusão. O primeiro pecado* a se cometer é fugir ao tema proposto, o segundo é lançar ideias contraditórias e o terceiro é deixar perguntas de serem respondidas. Ou seja, ao não estruturamos estamos fadados a perder o rumo. Vamos realizar um pequeno exercício para expor melhor essa ideia.

Vamos escrever sobre os benefícios em se adquirir um animal de estimação e desejamos convencer os pais (ou a/o parceira/o) dessa aquisição. Teremos de escolher um animal: Gato. Sei que é bem diferente de outros animais pois o gato sofre com ADORO ou ODEIO, não existe um meio termo, por isso mesmo o escolhi para esse animal. O próximo passo, é a estruturação das ideias em um mapa mental conforme imagem a seguir:


Agora que temos estruturada a ideia, deixamos fluir nosso texto:

Existem vantagens ao se adotar um gato como animal de estimação. Entre elas duas se destacam, a primeira como companhia pois uma vez estabelecida a relação de confiança, um gato torna-se o companheiro ideal tanto para adultos como para crianças. E a segunda por sua fácil adaptação ao espaço existente.

Atraentes como companhia combinam uma profunda afeição por seu dono com um forte senso de independência. Demonstram ser um ombro amigo para ouvir as reclamações e reconfortar com seu carinho. Em contrapartida, é um animal independente na dose certa e, diferente de outros animais de estimação, não ficam estressados longe da presença de seu dono.

Outro fator interessante e a sua adaptação a qualquer espaço, o que os tornam animais ideais para quem vive em apartamentos. Não existe a necessidade de levá-los a passeios constantes ao ar livre, e são animais limpos que praticam regularmente a higiene. É possível aprender sobre paciência, visto que para ensiná-lo de nada adianta gritos ou espancamentos e uma vez ensinados, aprendem a viver sob as regras da casa.

A responsabilidade em se cuidar de um animal reflete em outras áreas da vida, permanecendo como uma experiência importante e gratificante. Um gato, possui certo ar de mistério, altivez e não submissão e o torna a escolha mais atraente e fascinante que qualquer outro animal de estimação.


Ou seja, se seguirmos o esquema descrito no Mapa Mental não existe maneira de incorrermos em nenhum dos pecados citados e desta forma conseguimos um texto livre de problemas.

(*) Só para deixar claro, a melhor professora de português que tive me passou essa relação dos "Sete Pecados Capitais de uma Redação" e sempre uso em qualquer situação oficial que me encontre:
1º) Não fuja ao tema.
2°) Não se contradiga.
3º) Se perguntar! Responda!
4º) Não utilizar a 1ª e 2ª pessoa do singular ou plural.
5º) Tenha domínio sobre o assunto.
6º) Não encha linguiça (ou enrole).
7º) Não use etc (para o examinador isso significa: Eu Tou Chutando!).

Obrigado e até a próxima
Fernando Anselmo

terça-feira, 1 de abril de 2014

Desktop Publishing - Como criar índices no Scribus

Para editar a RSE utilizo um software conhecido como Scribus (veja mais aqui). Optei na RSE não criar índices, porém em algumas publicações tive que fazê-lo. Vamos aos passos para produzi-lo:
  1. Criar um Quadro de Texto.
  2. Nomear o quadro criado (ex. QuadroIndice).
  3. Selecionar "Arquivo | Configurações de Documento" no menu principal.
  4. Selecionar "Atributos de item do documento" e adicionar um atributo com nome "EntradaIndice" do tipo String.
  5. Selecionar: "Tabela de conteúdos e índices", pressionar o botão "Adicionar" e chamar de "MeuIndice". No nome do atributo do item selecionar "EntradaIndice" e no item "Posicionamento dos números de página" selecionar "QuadroIndice".
  6. Em cada quadro de texto clicar com o botão direito do mouse, selecionar "Atributo" e pressionar o botão "Adicionar".
  7. Para o campo "Nome" selecionar "EntradaIndice" e para o campo valor o campo "Valor" o que deseja que apareça no índice.
  8. Ao adicionar todas as entradas, selecionar o quadro de texto que receberá as entradas.
  9. Selecionar a opção "Extras | Gerar tabela de conteúdos" no menu principal.
  10. Selecionar todo o texto (CTRL+A) e na régua, criar uma tabulação (posicionar o cursor na régua) e posicionar aonde deseja a tabulação.
Desta forma suas revistas podem ganhar mais personalidades.

Obrigado e até a próxima
Fernando Anselmo

sábado, 29 de março de 2014

REST - Básico sobre node.js

Algumas pessoas me escreveram pedindo algumas aulas básicas sobre o node.js, então vamos começar uma pequena série sobre este software. Devemos primeiro saber que para aprender o node.js é necessário possuirmos um bom conhecimento de JavaScript, então considerarei esse como um pré-requisito.

Instalação do node.js


No site oficial do node.js podemos baixar gratuitamente a última versão disponível, como é um arquivo executável basta seguir as instruções do instalador, ao término abra uma janela de comando e digite:
node -v
Se a resposta for o número da versão corrente, então o node.js foi instalado sem problemas.

Criação do Servidor


Como vimos nas aulas práticas de REST, uma das funções primárias do node.js é a criação de um Servidor Web, este tipo de servidor simplesmente fica "escutando" em uma determinada porta alguma solicitação realizada - passo conhecido como REQUEST - e ao recebê-la busca fornecer a resposta  adequada - passo conhecido como RESPONSE.

Com simples comandos podemos criar um Servidor Web com o node.js, basta realizarmos três passos:
  1. Criar uma variável que representa o módulo http.
  2. Definir o que este servidor fará.
  3. Ativar o servidor em alguma porta.
Vamos então criar uma pasta (utilize nomes de pastas e subpastas simples, sem espaços ou acentuação) chamada servNode e dentro desta crie um arquivo chamado server.js com a seguinte codificação:
var http = require('http');

var server = http.createServer(function(req, res) {
  res.writeHead(200, {"Content-Type": "text/html; charset=UTF-8"});
  res.write("<h1>Meu primeiro teste com NodeJS!</h1>");
  res.end();
});

server.listen(3000, function() {
  console.log("Servidor do NodeJS ativo...");
});
Na janela de comandos acesse esta pasta e digite:
node server.js
Como resposta deve mostrar que o servidor está ativo. Observe que o código está dividido em 3 partes, cada uma representa um passo:
  1. Para um módulo qualquer do node.js usamos o método require() e criamos uma variável que recebe um objeto que representa o módulo chamado. 
  2. Um servidor é criado a partir do método createServer que como parâmetro define uma função com duas variáveis que representa objetos das ações request (objeto req) e response (objeto res). Através do objeto de response podemos definir o que desejamos transmitir como resposta, então quando o servidor estiver funcionando enviaremos uma resposta HTML com uma mensagem. O método end() finaliza, empacota e envia a resposta para o cliente. 
  3. Por fim ativamos o servido com o método listen() e informamos qual porta o servidor escutará nossas ações (neste caso na 3000).
Em um navegador digite o endereço: http://localhost:3000, e veremos a seguinte tela:


Na próxima aula aprenderemos como ler e criar arquivos com o node.js.

Obrigado e até a próxima
Fernando Anselmo



sábado, 8 de março de 2014

Android - Projeto 51 - Faltam (2ª Parte)

Na postagem passada vimos a criação da janela principal do projeto com uma primeira montagem. Nesta faremos algumas adaptações para concluirmos o projeto.

Camada das Funções

A primeira camada que vamos criar corresponde as funções que necessitamos. No caso deste projeto, funções de tratamento com Datas. Criamos uma nova classe no pacote projeto.livro.faltam chamada UtilData com a seguinte codificação:
public class UtilData {

  private static Date dataAtual = new Date();

  private static String formatarData(final Date data) {
    DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.UK);
    return sdf.format(data);
  }

  private static Date strToDate(final String dataStr) {
    DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.UK);
    try {
      return sdf.parse(dataStr);
    } catch (Exception e) {
      Log.e("Faltam", "Erro na data: " + e.getMessage());
    }
    return null;
  }

  public static Date convDiaMesToDate(final String diaMes) {
    Calendar original = new GregorianCalendar();
    original.setTime(dataAtual);
    int anoAtual = original.get(Calendar.YEAR);
    String montaData = diaMes.substring(0, 2) + "/" + diaMes.substring(2) + "/"
        + anoAtual;
    return strToDate(montaData);
  }

  public static Date convDiaToDate(final String dia) {
    Calendar original = new GregorianCalendar();
    original.setTime(dataAtual);
    int diaAtual = original.get(Calendar.DAY_OF_MONTH);
    int mesAtual = original.get(Calendar.MONTH);
    int anoAtual = original.get(Calendar.YEAR);
    if (diaAtual > Integer.parseInt(dia)) {
      mesAtual++;
      if (mesAtual > 11) {
        mesAtual = 0;
        anoAtual++;
      }
    }
    mesAtual++;
    String montaData = dia + "/"
        + ((mesAtual < 10) ? "0" + mesAtual : mesAtual) + "/" + anoAtual;
    return strToDate(montaData);
  }

  public static String retornarDiferencaComAtual(final Date dataOri) {
    // Data é hoje
    if (formatarData(dataAtual).equals(formatarData(dataOri))) {
      return "É hoje";
    }
    Calendar diaCirc = new GregorianCalendar();
    diaCirc.setTime(dataAtual);
    int dia = 0;
    while (!formatarData(diaCirc.getTime()).equals(formatarData(dataOri))) {
      diaCirc.add(Calendar.DAY_OF_MONTH, 1);
      dia++;
    }
    return dia + (dia > 2 ? " dias" : " dia");
  }
}
Os métodos desta classe são:
  • formatarData(final Date data): converter um objeto do tipo Date para um objeto tipo String no formato DD/MM/AAAA.
  • strToDate(final String dataStr): converter um objeto tipo String no formato DD/MM/AAAA para um objeto tipo Date.
  • convDiaMesToDate(final String diaMes): converter um objeto tipo String no formato DDMM (Dia e Mês) para um objeto tipo Date.
  • convDiaToDate(final String dia): converter um objeto tipo String no formato DD (Dia) para um objeto tipo Date. Se o dia informado for menor que o dia atual o mês será o atual, caso contrário o mês será o seguinte.
  • retornarDiferencaComAtual(final Date dataOri): retornar quantos dias faltam para chegar até o dia atual, recomenda-se que este método seja utilizado somente para períodos de um ano.
Java trata objetos tipo Date com duas classes: Calendar e GregorianCalendar. Se observamos veremos que todos os métodos contidos na própria Date estão depreciados, então usamos basicamente essas duas classes para lidar com esse tipo de objeto. Já as conversões para o tipo String são tratadas pela classe: SimpleDateFormat.

Camada de Dados

Precisamos realizar uma pequena modificação no método toString() da classe Registro, modificá-lo para a seguinte codificação:
  @Override
  public String toString() {
    if (dia.length() == 2) {
      return descricao + ": "
          + UtilData.retornarDiferencaComAtual(UtilData.convDiaToDate(dia));
    } else {
      return descricao + ": "
          + UtilData.retornarDiferencaComAtual(UtilData.convDiaMesToDate(dia));
    }
  }
Agora a diferença de dias já pode ser visualizada sem problemas na lista.

Uma boa prática é separar os métodos de Gravação e Leitura de arquivo e isolá-los em uma nova classe no pacote projeto.livro.faltam chamada UtilArquivo com a seguinte codificação:
public class UtilArquivo {

  protected static void carregarLista(final List<registro> lista,
      final FileInputStream arquivo) throws Exception {
    ObjectInputStream ois = null;
    try {
      ois = new ObjectInputStream(arquivo);
      Registro reg;
      do {
        reg = (Registro) ois.readObject();
        lista.add(reg);
      } while (true);
    } catch (EOFException e) {
    } finally {
      ois.close();
    }
  }

  protected static void gravarLista(final List<registro> lista, 
      final FileOutputStream arquivo) throws Exception {
    ObjectOutputStream oos = null;
    try {
      oos = new ObjectOutputStream(arquivo);
      for (Registro regs : lista) {
        oos.writeObject(regs);
        oos.flush();
      }
    } finally {
      oos.close();
    }
  }
}
São os mesmos métodos que já vimos na postagem anterior. Isolados aqui, foram mais simplificados, ou seja, o método carregarLista() carrega todos os objetos do arquivo para a lista, enquanto que o método gravarLista() grava todos os objetos da lista para o arquivo.

Atividade Principal

Para finalizarmos nosso aplicativo, procederemos mudanças na classe MainActivity:
public class MainActivity extends ListActivity {

  private EditText edDescricao;
  private EditText edDia;
  private final List<registro> lista = new ArrayList<registro>();
  private ListView listaRegs;

  private void eliminarRegistro() {
    for (int i = listaRegs.getCount(); i > -1; i--) {
      if (listaRegs.isItemChecked(i)) {
        lista.remove(i);
      }
    }
    mostrarLista();
  }

  private void guardarRegistro() {
    lista.add(new Registro(edDescricao.getText().toString(), edDia.getText()
        .toString()));
    mostrarLista();
    edDescricao.setText("");
    edDia.setText("");
    edDescricao.requestFocus();
  }

  private void mostrarLista() {
    ArrayAdapter adaptador = new ArrayAdapter(this,
        android.R.layout.simple_list_item_checked, lista);
    listaRegs.setAdapter(adaptador);
  }

  @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);
    listaRegs = getListView();
    listaRegs.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    findViewById(R.id.guardar).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(final View v) {
        guardarRegistro();
      }
    });
    findViewById(R.id.eliminar).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(final View v) {
        eliminarRegistro();
      }
    });
  }

  @Override
  protected void onStart() {
    super.onStart();
    try {
      UtilArquivo.carregarLista(lista, openFileInput("dias.reg"));
    } catch (Exception e) {
      Log.e("Faltam", "Erro Leitura: " + e.getMessage());
    }
    mostrarLista();
  }

  @Override
  protected void onStop() {
    super.onStop();
    try {
      UtilArquivo.gravarLista(lista,
          openFileOutput("dias.reg", Context.MODE_PRIVATE));
    } catch (Exception e) {
      Log.e("Faltam", "Erro Leitura: " + e.getMessage());
    }
  }
}
Vamos começar pelo método onCreate() que é chamado assim que o aplicativo é iniciado, a lista da tela é associada a um objeto do tipo ListView, sua visão também foi modificada permitindo que o usuário possa selecionar os registros que deseja excluir. Através do ciclo de vida o próximo método chamado é o onStart() que será responsável por carregar a lista do arquivo texto, e esta lista agora só será gravada quando o método onStop() for chamado (assim evitamos I/O desnecessários). O método mostrarLista() procede a atualização da lista na tela (devemos lembrar que estamos trabalhando com dois objetos o ListView e um List que não estão sincronizados).

Finalmente os dois métodos responsáveis pelas ações de Gravar e Eliminar os registros da lista através do pressionamento dos botões pelo usuário. O método guardarRegistro() adiciona um novo registro a lista e o método eliminarRegistro() verifica qual registro da lista foi selecionado pelo usuário e procede sua retirada (observe que o laço anda de trás para frente eliminando os registros, isso é feito pois tudo é posicional).


Pronto, podemos rodar sem problemas nosso projeto e inclusive passá-lo para o celular (não esqueça da diretiva android:installLocation=”auto” que permitirá que a aplicação seja colocada no cartão de memória.


Utilize este projeto para descobrir como:
  • Realizar gravações de objetos em arquivos;
  • Realizar a leitura de objetos em arquivos;
  • Utilizar o objeto tipo Date e suas conversões para o tipo String;
  • Utilizar lista com marcadores tipo Check;
  • Incluir e eliminar dinamicamente registros em listas.
Obrigado e até a próxima
Fernando Anselmo

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