Como fazer um app de cronômetro em Android

Primeiramente, a pergunta que você deve estar se fazendo: por que eu iria querer fazer um app de cronômetro?

Um app de cronômetro, genérico, não tem lá muita serventia uma vez que já existem soluções semelhantes. Mas pense que, dentro de um contexto e com as modificações adequadas, um app de cronômetro, por exemplo, pode virar um app de corrida, que registra as suas metas e os tempos alcançados. Pode virar um app de musculação, para ajudar a controlar o tempo de descanso entre as séries. Pode virar um app de natação e outros esportes de resistência, para medir o seu progresso (resistência, apnéia, etc).

Ou seja, eu te ensino como programar o app de cronômetro em Android, mas o que você vai fazer com esse conhecimento, aí fica por conta da sua criatividade e veia empreendedora!

Requisitos: para conseguir acompanhar este tutorial você já deve saber usar componentes de tela, saber programar Java, ter o Android Studio instalado na sua máquina e funcionando (outras opções menos poderosas são NetBeans e Eclipse) e saber usar RecyclerView. Use os links fornecidos para mais informações ou aprenda tudo isso e muito mais em meu livro de Android.

Vamos ver neste tutorial:

  1. Criando o projeto
  2. Tela do cronômetro
  3. Tela do histórico
  4. Funcionando

Vamos lá!

#1 – Criando e configurando o projeto

Crie um novo projeto no Android Studio com o nome de Cronometro. Quando ele pedir para criar a MainActivity, escolha o template Tabbed Activity e na tela seguinte, selecione a opção Action Bar Tabs (with View Pager).

Tabbed Activity
Tabbed Activity

Isso irá criar para você toda a lógica e estrutura básica para ter aquela experiência de uma tela só, com abas que você pode acessar tanto clicando no nome da mesma como deslizando pro lado com o dedo (swipe). Todo esse funcionamento já vem pronto neste template de Activity, apenas temos de personalizar o fragment principal que vem de exemplo de acordo com as nossas necessidades de tela e de pois criar o segundo fragment pra tela de histórico das “cronometradas”. Faremos isso mais tarde.

Primeiro, vamos ajustar os títulos e quantidade de abas.

Fazer isso é bem simples, abra a classe MainActivity.java e procure por uma classe interna chamada SectionsPagerAdapter. Dentro dela você vai encontrar um método getCount() que deve retornar 2 ao invés de 3, e um método getPageTitle com o switch/case que define os títulos das abas, mude para Cronômetro e Histórico, apagando o excedente.

A sua SectionsPagerAdapter deve ficar da seguinte forma:

Se você executar esse projeto agora, já verá que ele possui algumas funcionalidades toscas, como mudar o texto central conforme a aba e a navegação entre as abas funciona com swipe e com o toque no nome da mesma.

Mas vamos adiante!

#2 – Tela do cronômetro

Agora vamos personalizar nossa primeira tela.

activity_main.xml é o template padrão para todas telas, então remova o Floating Button desse arquivo de layout, pois não queremos que ele apareça em todas telas, mas apenas na principal.

No fragment_main.xml, que representa a primeira view da nossa interface com abas, a view do cronômetro, devemos ter um TextView com o tempo do cronômetro correndo e um botão para iniciar/parar o mesmo (você pode pensar em mais botões se quiser). Como na tela abaixo:

Tela Cronômetro
Tela Cronômetro

A ideia é a seguinte: o usuário aperta o Play (id:fab), o botão vira Stop e o tempo começa a correr (id:section_label). Quando ele tocar no botão de Stop, ele vira Play novamente, o tempo pára e é registrado na outra tela que lista os tempos realizados (tela de histórico).

Sendo assim, o fragment_main.xml abaixo dá conta do recado:

Para fazer funcionar essa tela não é muito complicado. Mas também não é muito simples, tem de fazer direito senão não funciona!

Dentro da MainActivity você vai encontrar uma classe estática interna chamada PlaceholderFragment, vamos começar declarando algumas variáveis e constantes novas dentro dela:

Os tipos de algumas variáveis não serão reconhecidos. Apenas use o ALT+ENTER para adicionar os imports necessários no topo do seu projeto. A variável section_label é o display numérico do nosso cronômetro. A variável initialTime será usada mais tarde para calcular o tempo que deve ser exibido no display. Falarei do Handler mais tarde, as constantes falam por si só e o isRunning é uma flag que indica se o cronômetro está “correndo” ou não.

Na sequência, devemos criar um objeto Runnable (logo abaixo das variáveis anteriores), que nada mais é do que um objeto que executará um trecho de código (run()) em uma thread separada. Isso porque não podemos travar a thread da UI com nosso código que atualiza o display do cronômetro. Usar um Runnable é uma boa opção quando você precisa rodar algum código que não trave a tela e a variável Handler que declaramos anteriormente permitirá fazer a “ponte” do Runnable com a UI.

O run() da nossa thread é bem simples, apenas pega o tempo de execução atual, menos o tempo em que o start foi dado para descobrir há quanto tempo o cronômetro está correndo. Com essa informação, imprime no formato hh:mm no display e manda o handler avisar a tela da alteração.

Agora, vamos criar o método que configura o botão para que funcione no modelo start/stop que queremos. Coloque este método na mesma classe PlaceholderFragment que estamos customizando até o momento:

Neste método eu carreguei o display (section_label),  o handler, o botão start/stop (fab) e diss que quando ele for clicado faremos um teste: se o cronômetro estiver parado (!isRunning) nós iniciamos ele e mudamos seu ícone para o stop (eu usei um pause nativo do Android, mas pode usar uma imagem se quiser).

Caso o cronômetro já esteja correndo, ele pára, reseta o display e o ícone volta a ser o start.

E por fim, para que a tela seja carregada corretamente e os componentes sejam configurados (através do método que acabamos de criar), precisamos configurar o método onCreateView que já existe na classe PlaceholderFragment:

Esse método é chamado para criar cada uma das abas da nossa aplicação, sendo cada aba um fragment de layout, por isso que faço o teste pra saber se estou na aba inicial para configurar o cronômetro. Note que referenciei R.layout.fragment_history, que ainda não existe. Crie ele na pasta res/layout como um layout XML qualquer, usaremos ele mais tarde.

Teste sua aplicação, ela já deve estar funcionando como um cronômetro bem simples. Com poucos ajustes no objeto Runnable você consegue adicionar centésimos e milésimos de segundo, caso queira.

#3 – Tela do Histórico

Caso não tenha feito ainda, crie um layout XML chamado fragment_history.xml na pasta res/layout.

Vamos dizer que você esteja treinando para uma prova de resistência. Cada vez que você treina, deseja registrar quanto tempo conseguiu aguentar correndo, pedalando ou nadando, por exemplo. Esse registro é útil para ver se está tendo progresso na sua atividade física, pois em teoria, os tempos devem ser cada vez maiores. Ou o contrário, caso sejam treinos de velocidade.

Sendo assim, na tela de histórico vamos colocar uma lista com todas as execuções do cronômetro, registrando a data da execução e o tempo que o cronômetro marcava quando foi pausado.

Vamos usar aqui uma RecyclerView, que já usamos neste outro post. Primeiro, vamos criar um layout chamado history_item.xml que será o template utilizado para cada um dos itens do histórico:

O que resulta neste layout aqui:

history_item.xml
history_item.xml

Atenção aos ids utilizados: tempo para o texto maior, com o tempo que o cronômetro marcava quando foi parado e data, com a ocasião em que ele foi parado.

Agora que temos o template de um item da lista, vamos adicionar um RecyclerView ao nosso fragment_history.xml, definindo que ela deve usar o history_item.xml como template para seus itens. Nosso fragment_history.xml deve ficar assim:

Agora é a hora de programarmos para essa RecyclerView funcionar!

Vamos começar criando uma classe HistoryHolder.java para mapear os campos do history_item.xml para variáveis locais:

Com essa classe criada, vamos criar outra classe, desta vez a classe History, que vai representar um objeto do histórico (simplifiquei bastante aqui, pode usar tipos mais interessantes que String para os dois atributos):

E por fim, a classe que faz a união da HistoryHolder com a History: a HistoryAdapter!

Este adapter é bem simples de entender:

  1. no construtor esperamos a lista de objetos History que queremos listar;
  2. o método addHistory deve ser chamado sempre que a gente quiser adicionar um novo item na lista. Ele sempre adiciona no topo (últimos primeiros) e manda a lista se renderizar novamente;
  3. no onCreateViewHolder nós carregamos a classe HistoryHolder que criamos anteriormente;
  4. no onBindViewHolder nós fazemos o de-para do objeto History para o HistoryHolder (que por sua vez joga as informações no hostory_item.xml);
  5. por fim, o getItemCount() apenas retorna quantos elementos History nossa lista possui.

Para finalizar a exibição desta tela, vamos adicionar uma nova variável e um novo método na classe estática PlaceholderFragment que fica dentro da MainActivity.java:

A variável adapter foi declarada fora do método para que seja acessível por outros métodos mais tarde. Esse método setupHistory configura a RecyclerView, definindo que qualquer alteração no adapter deve repercutir na aparência da lista. Note que inicializei o adapter com um ArrayList vazio. Não vou entrar aqui em detalhes sobre persistência de dados local ou remota, coisa que já fiz em outros posts, consulte os links. Neste tutorial de hoje usarei apenas objetos em memória mesmo, o que quer dizer que se fechar o aplicativo e rodar de novo, ele vai iniciar zerado.

Agora apenas devemos chamar este método no onCreateView desta classe PlaceholderFragment. Temos de apenas mudar o trecho abaixo para incluir um else:

Isso é o suficiente para que a tela de histórico apareça vazia nos seus testes no Android Studio. No entanto, precisamos fazer a “conexão” entre ambas telas para que, cada vez que um novo tempo seja marcado no cronômetro, ele seja registrado nessa lista.

#4 – Funcionando

Para fazer a tela do cronômetro se comunicar com a tela de histórico é bem simples, apenas temos de utilizar a variável adapter que deixamos a nível de classe.

Quando você pausa o cronômetro, deve registrar as informações daquela execução e adicionar no adapter, como abaixo (edite o código presente no onClick do FloatingActionButton da PlaceholderFragment, por via das dúvidas incluí o método inteiro de setup do botão):

Apenas duas linhas foram alteradas nesse método inteiro, exatamente as duas logo após meu comentário “atualiza a recyclerView”. Aqui eu instancio um SimpleDateFormat pra definir o formato de data que aparecerá na interface e adiciono um novo histórico com o tempo que aparecia no display do cronômetro quando o mesmo foi pausado, bem como a data atual para registro.

Se você executar agora esse aplicativo no simulador e mandar rodar o cronômetro algumas vezes, quando você acessa a aba Histórico (seja tocando no nome da aba ou deslizando a tela pra direita) você deve ver algo parecido com abaixo:

RecyclerView Funcionando
RecyclerView Funcionando

E isso é tudo pelo tutorial de hoje.

Claro, existem inúmeras coisas que você pode fazer, sendo a mais óbvia salvar os dados na nuvem ou localmente no app. Mas tem outras mudanças que podem ser legais, desde personalizar essa interface bem simples, registrar os centésimos de segundo, criar gráficos de performance do atleta (uma feature paga!), incluir recursos de geolocalização pro atleta saber onde estava naquele treino ou até mesmo para calcular a distância percorrida (no caso de um cronômetro de corrida, caminhada ou ciclismo), entre muitas outras coisas.

Isso tudo eu deixo para você e sua criatividade!

Curtiu o post? Então dá uma olhada no meu livro de Android clicando no banner abaixo pra aprender a criar outros tantos apps incríveis!

Criando apps para empresas com Android

O que achou desse artigo?
[Total: 1 Média: 5]