Você está na página 1de 270

Desenvolvimento

de Aplicativos para
Dispositivos Móveis
RAFAEL MUNHOZ ALMEIDA DA SILVA

Editora

SÃO PAULO/ SP
DESENVOLVIMENTO DE
A P L I C AT I V O S PA R A
DISPOSITIVOS MÓVEIS

RAFAEL MUNHOZ ALMEIDA DA SILVA

Editora:

Editora

1º EDIÇÃO - 2021 | SÃO PAULO/ SP


DESENVOLVIMENTO DE APLICATIVOS
PARA DISPOSITIVOS MÓVEIS

EXPEDIENTE

COORDENAÇÃO GERAL COORDENAÇÃO DE


REVISÃO ORTOGRÁFICA
Nelson Boni
Esthela Malacrida

AUTOR(ES) COORDENAÇÃO,
PROJETO GRÁFICO E CAPA
Rafael Munhoz Almeida da
Silva João Guedes

1º EDIÇÃO - 2021 | SÃO PAULO/ SP

Ficha Catalográfica/ ISBN

CATALOGAÇÃO ELABORADA POR GLAUCY DOS SANTOS SILVA - CRB8/6353

Editora
Apresentação

Prezado Aluno,

V
ivemos na era dos aplicativos para dispositivos mó-
veis, hoje em dia os dispositivos móveis são muito
acessíveis economicamente e a maioria da popula-
ção possui pelo menos um destes dispositivos, o que gera
uma demanda muito alta do mercado por profissionais com
a habilidade de desenvolver este tipo de software.
Neste livro você vai entrar em contato com o desenvolvi-
mento de aplicativos para dispositivos móveis utilizando a
plataforma Android. Você verá como instalar o ambiente de
desenvolvimento oficial do Android que é o Android Studio.
Terá uma introdução sobre a nova linguagem oficial de
programação chamada Kotlin, aprenderá a usar o editor
de layout para construir interfaces gráficas e ao longo do
material irá desenvolver dois aplicativos.
Portanto desejo a você estudante, uma ótima leitura, e
que você se divirta ao conhecer um pedacinho deste enorme
mundo que é o de desenvolvimento de aplicativos para dis-
positivos móveis.

Bons Estudos!

4

SUMÁRIO:

UNIDADE 1:
PROGRAMANDO PARA O ANDROID���������������������������������1-1
CAPÍTULO 1:
INTRODUÇÃO AO ANDROID��������������������������������������������� 1-2
EXERCÍCIOS PROPOSTOS������������������������������������������������� 1-10
CAPÍTULO 2:
INTRODUÇÃO AO ANDROID STUDIO������������������������������������ 2-1
EXERCÍCIOS PROPOSTOS������������������������������������������������� 2-11

UNIDADE 2:
INTRODUÇÃO A LINGUAGEM KOTLIN�������������������������������3-1
CAPÍTULO 3:
VARIÁVEIS, TIPOS E OPERADORES������������������������������������ 3-2
EXERCÍCIOS PROPOSTOS������������������������������������������������� 3-21
CAPÍTULO 4:
CONTROLE DE FLUXO��������������������������������������������������� 4-1
EXERCÍCIOS PROPOSTOS������������������������������������������������� 4-12

UNIDADE 3:
APROFUNDANDO NA LINGUAGEM KOTLIN�������������������������5-1
CAPÍTULO 5:
LISTAS E FUNÇÕES������������������������������������������������������ 5-2
EXERCÍCIOS PROPOSTOS������������������������������������������������� 5-13
CAPÍTULO 6:
CLASSES������������������������������������������������������������������ 6-1
EXERCÍCIOS PROPOSTOS������������������������������������������������� 6-17
UNIDADE 4:
PRIMEIRO APLICATIVO: ÁLCOOL OU GASOLINA�������������������7-1
CAPÍTULO 7:
DEFININDO O LAYOUT��������������������������������������������������� 7-2
EXERCÍCIOS PROPOSTOS������������������������������������������������� 7-13
CAPÍTULO 8:
CODIFICANDO A ACTIVITY���������������������������������������������� 8-1
EXERCÍCIOS PROPOSTOS������������������������������������������������� 8-15

UNIDADE 5:
SEGUNDO APLICATIVO: LISTA DE COMPRAS����������������������9-1
CAPÍTULO 9:
RECYCLERVIEW E RECYCLERADAPTER������������������������������� 9-2
EXERCÍCIOS PROPOSTOS������������������������������������������������� 9-31
CAPÍTULO 10:
VISUALIZANDO E ADICIONANDO ITENS������������������������������ 10-1
EXERCÍCIOS PROPOSTOS������������������������������������������������ 10-26

UNIDADE 6:
PERSISTÊNCIA NO APLICATIVO LISTA DE COMPRAS����������� 11-1
CAPÍTULO 11:
CRIANDO A CAMADA DE PERSISTÊNCIA���������������������������� 11-2
EXERCÍCIOS PROPOSTOS������������������������������������������������ 11-12
CAPÍTULO 12:
INTEGRANDO A CAMADA DE PERSISTÊNCIA����������������������� 12-1
EXERCÍCIOS PROPOSTOS������������������������������������������������ 12-17

REFERÊNCIAS��������������������������������������������������������� 13-1

GABARITO������������������������������������������������������������� 14-1
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 1:
PROGRAMANDO PARA O ANDROID

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Nesta primeira unidade iremos dar início aos estudos, vere-


mos uma breve visão histórica do sistema operacional Android.
Nesta unidade também veremos de maneira geral a arquitetura
da plataforma.

Ótimos estudos!

Conteúdos da Unidade:
Evolução do sistema operacional Android, Visão geral da ar-
quitetura, Instalação do ambiente de desenvolvimento oficial,
Desenvolvimento do projeto Hello World.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 1:
INTRODUÇÃO AO ANDROID
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
1.1 O sistema operacional Android
No início dos anos 2000, os celulares estavam começando a
se popularizar, o tamanho dos aparelhos estava diminuindo, ou-
tras funcionalidades estavam sendo embarcadas nos aparelhos,
tais como agendas eletrônicas e até mesmo jogos.
Com o aumento da produção o custo dos aparelhos começou
a diminuir tornando o celular um dispositivo acessível a uma boa
parte da população.
Porém cada fabricante possuía o seu próprio sistema embar-
cado, ou seja, um aplicativo desenvolvido para um celular de um
determinado fabricante não seria compatível com outro dispositi-
vo de outro fabricante.
Ou seja, para que um aplicativo funcionasse em vários dispo-
sitivos ele teria que ser reescrito e recompilado, gerando custo de
desenvolvimento e manutenção.
Já prevendo que o smartphone nasceria em breve o primeiro
sistema operacional comum foi criado. Este sistema é o Symbian,
que possuía código fechado, os aplicativos escritos para ele deve-
riam usar a linguagem C++.
Alguns anos mais tarde nasce o Android, que é um sistema
operacional aberto, ou seja, os fabricantes poderiam customizá-lo,
diferente do Symbian que era fechado.
Os aplicativos para o sistema operacional Android podem ser
escritos em C++ e Java.
Existem várias teorias que descrevem o sucesso do Android
sobre o Symbiam, algumas dizem que o Android foi mais aceito
pois era mais fácil de desenvolver aplicativos, pois o framework,

1-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
que são as ferramentas que usamos para fazer campos de texto,
tablets etc, eram mais fáceis de entender.
E na época a linguagem Java tinha uma curva de aprendiza-
do bem menor que a linguagem C++.
Algumas teorias afirmam que o Android, por ser um sistema
operacional de código fonte aberto, ou seja, por poder ser custo-
mizado pelos fabricantes foi mais bem aceito e se espalhou pela
maioria deles.
Quando o Android foi lançado para uso público, ele já pos-
suía todo um ecossistema para a distribuição dos aplicativos, ou
seja, era muito mais fácil encontrar e instalar aplicativos para os
dispositivos baseados em Android do que para os dispositivos
Symbian, alguns analistas dizem que esse foi o principal fator que
fez do Android o sistema operacional mais popular para dispositi-
vos móveis.

1.1.1 Evolução do sistema Android


O sistema android já possui aproximadamente 13 anos, du-
rante este tempo várias versões foram lançadas e cada uma delas
possui um apelido, baseado no nome de um doce. Veja na tabela
abaixo o resumo com todas as versões lançadas:

Tabela 1-1: Evolução das versões do Android


Versão Apelido Lançamento API
11 Android 11 (R) 8 de setembro de 2020[231] 30
10 Android 10 (Q) 3 de setembro de 2019 29
9 Pie 6 de agosto de 2018 28

1-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
Versão Apelido Lançamento API
8.1 15 de dezembro de 2017 27
Oreo
8.0 21 de agosto de 2017 26
7.1.x 5 de dezembro de 2016 25
Nougat
7.0.x 22 de agosto de 2016 24
6.0.-6.0.1 Marshmallow 05 de Outubro de 2015 23
5.1-5.1.1 10 de março de 2015 22
Lollipop
5.0-5.0.2 12 de novembro de 2014 21
4.4-4.4.4 KitKat 31 de outubro de 2013 19
4.3.x 24 de julho de 2013 18
4.2.x Jelly Bean 13 de novembro de 2012 17
4.1.x 9 de julho de 2012 16
4.0.3–4.0.4 Ice Cream Sandwich 16 de dezembro de 2011 15
2.3.3–2.3.7 Gingerbread 9 de fevereiro de 2011 10
2.2-2.2.3 Froyo 20 de maio de 2010 8
2.0-2.1 Eclair 26 de outubro de 2009 5
1.6 Donut 15 de setembro de 2009 4
1.5 Cupcake 27 de abril de 2009 2
1.0-1.1 Petit Four ou Beta 23 de setembro de 2008 1

Fonte: https://pt.wikipedia.org/wiki/Android

1.2 Arquitetura da plataforma Android


Podemos dividir a plataforma Android em várias camadas
com diferentes níveis de abstração, veja abaixo a figura com essas
camadas, começando do nível de abstração maior para o menor:

1-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D

Figura 1-1: Android Studio

1-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
1.2.1 System Apps
Nesta camada encontraremos os aplicativos tais como o
Dialer (Aplicativo de telefone), aplicativo de e-mail,
aplicativo de calendário entre outros.
Como o Android possui o código fonte aberto, podemos
modificar estes aplicativos para satisfazer as necessidades de um
determinado fabricante, como por exemplo podemos modificar o
aplicativo de telefone para que ele recuse chamadas de números
considerados indesejáveis.

1.2.2 Java API Framework


Quando criamos um aplicativo Android usando tanto a lin-
guagem Java quanto a linguagem Kotlin não precisamos nos pre-
ocupar com elementos básicos de visualização, como campos de
texto, listas entre outros elementos tais como as bibliotecas de no-
tificação localização e até mesmo as classes do tipo Activity que
representam cada tela da aplicação Android.
Mais adiante no material você vai aprender mais sobre o que
são classes e o mais importante o que é uma classe do tipo Activity.
Durante o desenvolvimento dos projetos deste livro você
criará e usará muito as classes do tipo Activity.

1.2.3 Native C/C++ Libraries / Android Runtime


É nessa camada que estão as bibliotecas implementadas em
C/C++, temos por exemplo nesta camada, a biblioteca OpenGL
ES, muito utilizada em computação gráfica.

1-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
A biblioteca Webkit utilizada no processamento de páginas
html, código javascript entre outras funcionalidades de um
browser de internet.
As bibliotecas desta camada também podem ser acessadas
por meio da linguagem Java, na camada Java API Framework.
A Android Runtime (ART) é a máquina virtual que processa
o bytecode do Java/Kotlin. Quando um aplicativo é compi-
lado para a plataforma Android, tanto na linguagem Java quanto
na linguagem Kotlin, teremos como produto um arquivo do tipo
.DEX é neste arquivo que teremos o bytecode do código que será
lido pela ART.
Podemos também desenvolver aplicativos nativos para esta
camada utilizando o Android NDK, ou seja, podemos escrever di-
retamente código C++ que será compilado pelo NDK.

1.2.4 Hardware Abstraction Layer (HAL)


Aqui encontramos as abstrações dos dispositivos do sistema
tais como sensores, câmera de vídeo, bluetooth entre outros. Cada
um destes dispositivos vai prover nesta camada uma interface para
que ele possa ser acessado por código Java ou Kotlin.
Um exemplo é quando queremos abrir a câmera em nosso
aplicativo, usaremos a linguagem Kotlin ou Java para manipular a
interface deste hardware que é fornecida pela camada HAL.

1.2.5 Linux Kernel


Como última camada da arquitetura temos o kernel do linux,
que fornece a todas as camadas acima, funcionalidades de sistema

1-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 1

IN TR O D U Ç ÃO AO AN D R O I D
operacional como gerenciamento de memória, controle de proces-
sos entre outras.
É nesta camada que os fabricantes também desenvolvem
os drivers específicos para o hardware dos dispositivos. Como
por exemplo um fabricante desenvolve um telefone novo, com um
novo controlador de rede, é na camada do kernel que ele vai imple-
mentar o novo driver para este novo hardware.

1-9
 EXERCÍCIOS PROPOSTOS

1) Escolha a alternativa correta sobre o sistema operacional Android:

(  ) -a) Este sistema operacional Android não possui código aberto.


(  ) -b) Não podemos usar a linguagem C++ para escrever aplicati-
vos para o sistema operacional Android.
(  ) -c) Um aplicativo escrito para um dispositivo em Android deve-
rá ser reescrito para outro dispositivo de hardware diferente
e mesma versão do Android.
(  ) -d) O Android é um sistema operacional de código aberto e pode
ser customizado por qualquer fabricante de celulares.
(  ) -e) A linguagem Java não pode ser mais utilizada no desenvolvi-
mento de aplicativos Android.

2) Escolha a alternativa correta sobre a API 30 do Android

(  ) -a) A API 30 ainda não foi lançada.


(  ) -b) A API 30 é da versão 8.1
(  ) -c) A API 30 foi lançada em 21 de agosto de 2017
(  ) -d) A API 30 foi lançada em 8 de setembro de 2020
(  ) -e) N.d.a.

3) Escolha a alternativa correta que afirma por que o sistema operacional


Android superou o sistema operacional Symbian:

(  ) -a) O sistema operacional Android superou o Symbian pois o


Android era um sistema de código fechado e não poderia ser
customizado pelos fabricantes, tornando ele muito mais ro-
busto pois seu código fonte não poderia ser modificado.
(  ) -b) Segundo os desenvolvedores, apesar do framework de de-
senvolvimento do Android ser mais complicado pois não
possui elementos já prontos como caixas de texto e botões,

1-10
o Android superou o Symbian pois seus aplicativos eram es-
critos em java.

EX ER C ÍC IO S PR O PO STO S
(  ) -c) O Android superou o Symbian por possuir um framework
completo com muitos elementos gráficos e outras bibliote-
cas como conexão de rede, acesso ao sistema de arquivos,
além de ser de código aberto e de possuir um ecossistema
completo para o download de aplicativos.
(  ) -d) O Android superou o Symbian apenas por possibilitar o de-
senvolvimento dos aplicativos usando a linguagem Java.
(  ) -e) Nda.

4) Qual é o nível de software que fornece para as outras camadas gerencia-


mento de memória e controle de processos:

(  ) -a) É a camada do Kernel do Linux.


(  ) -b) É a camada chamada HAL.
(  ) -c) É a System Apps.
(  ) -d) É a Java API Framework.
(  ) -e) É a Android Runtime.

5) Escolha a afirmativa correta sobre o arquivo DEX

(  ) -a) É neste arquivo que escrevemos o código fonte do nosso


aplicativo em Kotlin ou em Java.
(  ) -b) É neste arquivo que o compilador escreve o bytecode origi-
nário do código Kotlin ou Java que foi escrito, este arquivo
será processado diretamente no Kernel do Linux.
(  ) -c) É neste arquivo que o compilador escreve o bytecode origi-
nário do código Kotlin ou Java que foi escrito, este arquivo
será processado pela Android Runtime que está no nível das
bibliotecas de código nativo C/C++.
(  ) -d) Arquivos DEX não estão disponíveis na plataforma Android.
(  ) -e) N.d.a.

1-11
6) Quando criamos um aplicativo de lista de compra, para a plataforma

EX ER C ÍC IO S PR O PO STO S
Android escrito nas linguagens Java ou Kotlin, em qual camada este apli-
cativo pode ser classificado:

(  ) -a) Na camada Java API Framework, pois o código Java e o có-


digo Kotlin serão executados pela ART.
(  ) -b) Será classificado como a camada Android Runtime, pois este
código será executado pela máquina virtual implementada
neste nível.
(  ) -c) Este aplicativo de lista de compras será classificado na ca-
mada chamada System Apps.
(  ) -d) O aplicativo deverá ser classificado na camada Native C/C++
pois o código Kotlin ou Java vai virar código C/C++ depois
de compilado.
(  ) -e) O aplicativo será considerado como sendo da camada HAL
pois precisará acessar a tela e portanto terá que fazer uma
abstração de hardware.

7) Digamos que um fabricante vai lançar um novo hardware que mede a


temperatura do ambiente pelo celular, considere esta situação e escolha
abaixo a afirmativa correta

(  ) -a) O Fabricante deverá apenas criar um aplicativo na camada


System Apps para mostrar a temperatura.
(  ) -b) O Fabricante deverá modificar o Android Runtime, para que
o arquivo .DEX que possua o código deste novo sensor de
temperatura possa ser interpretado.
(  ) -c) O Fabricante deverá apenas criar uma abstração no nível
HAL e os desenvolvedores poderão acessar este novo sensor
em seus aplicativos.
(  ) -d) O Fabricante deverá incluir o código do driver no nível do
kernel do Linux e criar uma abstração na camada HAL. Com
isso já será suficiente para que um desenvolvedor crie um
aplicativo escrito em Java ou Kotlin para mostrar de forma
gráfica a temperatura do ambiente.
(  ) -e) O Fabricante deverá esperar o Google implementar o driver
do novo sensor de temperatura, pois o código do Android é
fechado.

1-12
8) Sobre a Android Runtime (ART) escolha a alternativa verdadeira.

EX ER C ÍC IO S PR O PO STO S
(  ) -a) A Android Runtime fica na camada JAVA API Framework
pois é a máquina virtual que executa os aplicativos compila-
dos em Java ou Kotlin.
(  ) -b) A Android Runtime fica no mesmo nível da camada Native
C/C++ e é responsável por executar o código compilado dos
aplicativos escritos em Java ou Kotlin.
(  ) -c) A Android Runtime executa apenas código compilado que
foi escrito na linguagem C/C++
(  ) -d) A Android Runtime não acessa as bibliotecas escritas em C/
C++
(  ) -e) A Android Runtime não processa arquivos do tipo .DEX

9) Sobre a Java API Framework, escolha a alternativa verdadeira

(  ) -a) Quando precisamos de um elemento gráfico, como por


exemplo um campo texto, utilizamos a Java API Framework.
(  ) -b) A Java API Framework é responsável pelo controle de me-
mória de baixo nível.
(  ) -c) A Android Runtime fica na camada da Java API Framework.
(  ) -d) Um aplicativo escrito em Kotlin não pode usar as classes da
Java API Framework.
(  ) -e) É na Java API Framework onde estão implementados os dri-
vers de controle do hardware.

10) Qual camada fornece uma abstração para o acesso do hardware que con-
trola a câmera de um dispositivo.

(  ) -a) A camada do Linux Kernel, pois é nela que os drivers estão


escritos.
(  ) -b) É na Java API Framework, pois a abstração está escrita em
Java.
(  ) -c) É na camada Hardware Abstraction Layer.
(  ) -d) As classes de abstração para o acesso ao hardware estão es-
critas na camada de System Apps.
(  ) -e) N.d.a.

1-13
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 2:
INTRODUÇÃO AO ANDROID STUDIO
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
2.1 Instalando e utilizando o Android Studio
No início a plataforma Android não possuia uma IDE (In-
tegrated Development Environment), ou seja, cabia ao de-
senvolvedor baixar todas as ferramentas necessárias, tais como o
Java, o SDK do Android, o Emulador do Android, e alguma outra
ferramenta que integrava todas essas, geralmente era utilizado o
Eclipse com um plugin para o desenvolvimento Android.
Isso tudo mudou quando o Android Studio foi criado, basea-
do no IntelliJ, o Android Studio baixa automaticamente todas
as ferramentas necessárias para o desenvolvimento de aplicati-
vos Android.
O Android Studio pode ser instalado nos sistemas operacio-
nais Windows, Mac OS e Linux, para isso acesse o link https://
developer.android.com/studio e baixe o executável de instalação
do sistema operacional que você está utilizando e siga os passos
da instalação.
Quando a instalação terminar, execute o aplicativo do An-
droid Studio, você deverá ver algo similar a figura abaixo no mo-
mento da execução:

2-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
Figura 2-1: Android Studio

2.1.1 Primeiro projeto Android


Agora que temos o Android Studio instalado e rodando, te-
mos tudo o que precisamos para criar o nosso primeiro projeto,
este projeto será bem simples pois apenas mostrará na tela do dis-
positivo móvel o texto: “Olá Mundo”.
Para isso, clique no botão New Project, escolha a opção
Phone and Tablet e em seguida a opção Empty Activity,
com as duas opções selecionadas clique no botão Next, como
mostrado na figura abaixo:

2-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
Figura 2-2: Criando novo projeto

Na próxima tela você deverá dar um nome ao seu aplicativo,


vamos chamá-lo de OlaMundo, este texto vai no campo Name.
O próximo campo chamado Package Name, é o nome do
pacote básico do seu projeto, o texto que vai aqui é geralmente o in-
verso de um domínio, que pode ser o domínio de uma página do seu
aplicativo, no meu caso eu vou colocar um possível domínio inver-
tido para o meu aplicativo, que vai ser com.munhra.olamundo.
Vamos deixar o campo Save Location, do jeito que ele
está, certamente o do projeto que você criou é bem diferente do
valor da imagem, mas não se preocupe, não precisa modificar esse
campo, a não ser que você deseje colocar o aplicativo em outro local.
O campo Language é importante, no capítulo anterior disse-
mos que os aplicativos escritos para a plataforma Android podem

2-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
ser escritos em C++ e Java, porém desde 2017 a linguagem Kotlin
foi anunciada como sendo a linguagem oficial do Android, por isso
vamos deixar o campo Language com o valor Kotlin. Falaremos
muito mais sobre a linguagem Kotlin nos próximos capítulos.
Por fim, vamos usar como SDK mínimo a API 21, portanto
basta deixar o campo Minimum SDK com esse valor ou modificá-lo
caso este não seja o seu valor.
Depois de revisarmos todas estas informações podemos cli-
car no botão Finish, para que o Android Studio crie o esqueleto
da nossa primeira aplicação.

Figura 2-3: Configurando o novo projeto

2-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
2.1.2 Conhecendo o Android Studio
Quando clicamos no botão Finish, o Android Studio nos
leva para tela de projeto, perceba que basicamente esta tela é divi-
dida em duas grandes partes, do lado esquerdo temos o navegador
de projeto, por meio dessa interface podemos navegar pelos arqui-
vos do projeto.
Do lado direito será mostrado o conteúdo de um arquivo que
foi selecionado do lado esquerdo. A figura abaixo mostra a tela do
Android Studio.

Figura 2-4: Tela principal do Android Studio.

No canto superior esquerdo temos a perspectiva do projeto


configurada para a opção Android, vamos manter essa opção pois
é a melhor quando vamos desenvolver aplicativos.
Logo abaixo temos a pasta app, é nesta pasta que estão as in-
formações necessárias para a construção do aplicativo, tais como,

2-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
os arquivos que implementam a sua lógica, os recursos gráficos
como layout de tela e imagens etc.
Bem no final temos a pasta Gradle Scritps, o Gradle é
um gerenciador de construção e de bibliotecas utilizado no Android
Studio e nessa pasta temos os arquivos que fazem a sua configuração.

2.1.3 O arquivo MainActivity


Vamos dar uma atenção especial ao arquivo MainActivi-
ty, este é o arquivo responsável por ler o código do layout da tela
que está definido no arquivo activity_main.xml e desenhar a
tela principal baseado nos componentes deste arquivo.
Além disso, é o arquivo MainActivity que é responsável
pelo ciclo de vida do nosso primeiro projeto. Você não vai entender
tudo o que este arquivo faz, mas vale a pena começarmos aqui uma
explicação alto nível, considere abaixo o código deste arquivo:

1| package com.munhra.olamundo
2|
3| import androidx.appcompat.app.
AppCompatActivity
4| import android.os.Bundle
5|
6| class MainActivity : AppCompatActivity() {
7|  
override fun onCreate(savedInstanceS-
tate: Bundle?) {
8|   
super.onCreate(savedInstanceState)

2-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
9|   
setContentView(R.layout.
activity_main)
10|  }
11| }

Na linha 1 declaramos o package ao qual pertence o arquivo,


por hora vamos pular a linha 3. Na linha 4 importamos a classe
Bundle que é usada pela Activity para recuperar seu estado, não
se preocupe, pois o Android cuida disso automaticamente.
A declaração mais importante deste arquivo acontece na li-
nha 6, pois é nessa linha que é declarada a classe MainActivi-
ty, classe é um conceito de Programação Orientada a Objetos, este
conceito será introduzido nos capítulos posteriores.
Veja que a classe MainActivity, herda as propriedades e
métodos da classe AppCompatActivity, essa classe foi importa-
da na linha 3.
Podemos pensar que a classe AppCompatActivity é uma
activity porém ela mantém possibilita ao aplicativo, usar recur-
sos novos em versões anteriores da API.
Quando tocamos no ícone da aplicação, o Android, procura
na MainActivity o método onCreate, e executa ele, por isso na
linha 7 este método foi sobrescrito.
Toda a vez que sobrescrevemos um método devemos, logo na
primeira linha fazer uma chamada para o mesmo método da classe
mãe por isso utilizamos a palavra chave super, para fazer referên-
cia a classe mãe e deste modo chamamos o método onCreate da
classe mãe, isto foi feito na linha 8.
A linha mais importante da sobrescrição do método onCre-
ate é a linha 9, Veja que chamamos o método setContentView

2-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
da classe MainActivity, este método é responsável por de-
senhar os elementos da tela que estão definidos no parâmetro
R.layout.activity_main.
Este parâmetro é uma referência para o arquivo activity_
main.xml que está na pasta res/layout. É neste arquivo que os
elementos gráficos estão definidos, no caso deste primeiro aplicati-
vo temos apenas um componente do tipo TextView, que será res-
ponsável por mostrar o texto “Hello World!” na tela do dispositivo.

2.1.4 Executando o arquivo no emulador


Agora que passamos a principal parte do código, vamos exe-
cutar o aplicativo e ver o que acontece, não é necessário um dispo-
sitivo real, precisamos apenas baixar e instalar uma das versões do
AVD (Android Virtual Device) para rodar nosso aplicativo.

Figura 2-5: Ícone do AVD.

Feito isto uma tela de gerenciamento dos dispositivos virtu-


ais vai se abrir, clique no botão Create Virtual Device, e siga
as instruções. Isso pode levar um tempo, pois o Android Studio

2-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 2

IN TR O D U Ç Ã O A O A N D R O ID ST U D I O
vai fazer o download dos arquivos necessários e depois instalar.
Quando este processo terminar, vamos finalmente executar o nos-
so primeiro programa, para isso clique no botão indicado na fi-
gura abaixo:

Figura 2-6: Ícone para rodar o aplicativo.

Após clicar no ícone play, o emulador do Android executará


o aplicativo e poderemos ver na tela o texto “Hello World!” na tela
do emulador.

2-10
 EXERCÍCIOS PROPOSTOS

1) Qual é a IDE oficial para o desenvolvimento de software para a plataforma


Android?

(  ) -a) Eclipse
(  ) -b) Visual Studio
(  ) -c) XCode
(  ) -d) Android Studio
(  ) -e) Unity

2) Qual é a linguagem oficial para o desenvolvimento de aplicativos para a


plataforma Android?

(  ) -a) Java
(  ) -b) Java Script
(  ) -c) C/C++
(  ) -d) C#
(  ) -e) Kotlin

3) Escolha a afirmativa correta sobre o arquivo MainActivity.kt

(  ) -a) O arquivo MainActivity é responsável apenas por armazenar


o layout da tela principal do aplicativo.
(  ) -b) Dentro do arquivo MainActivity está escrita a classe de mes-
mo nome que é responsável por controlar o ciclo de vida da
tela principal deste aplicativo.
(  ) -c) Não devemos nunca sobrescrever o método onCreate, utili-
zando a palavra chave override, pois desta maneira estare-
mos quebrando o ciclo de vida da MainActivity.
(  ) -d) A classe MainActivity, escrita dentro do arquivo de mesmo
nome, deverá sempre ser escrita em Java.

2-11
(  ) -e) O arquivo de Layout nunca deverá ser utilizado no código
sobrescrito do método onCreate.

EX ER C ÍC IO S PR O PO STO S
4) Escolha a afirmativa correta sobre o arquivo activity_main.xml

(  ) -a) É neste arquivo que está escrito o código que define o layout
da tela.
(  ) -b) É neste arquivo que escrevemos o código em Java que con-
trola o ciclo de vida da MainActivity do aplicativo.
(  ) -c) Arquivos .xml não podem ser usados em projetos de aplica-
tivos Android.
(  ) -d) Quando damos o mesmo nome que o arquivo MainActivity
não precisamos sobrescrever o método onCreate para ins-
tanciar os elementos do layout.
(  ) -e) Quando chamamos o método setContentView, devemos pas-
sar uma String, ou seja, um valor entre aspas duplas indican-
do o caminho absoluto para o arquivo activity_main.xml.

5) Considere o código abaixo e escolha a afirmativa correta

6| class MainActivity : AppCompatActivity() {


7|  override fun onCreate(savedInstanceS-
tate: Bundle?) {
8|    super.onCreate(savedInstanceState)
9|    setContentView(R.layout.activity_main)
10|  }
11| }

(  ) -a) A definição da classe MainActivity está errada pois deve ser


escrita em Java.
(  ) -b) A declaração da classe MainActivity está errada pois
ela não pode herdar os atributos e métodos da classe
AppCompatActivity.
(  ) -c) A declaração da linha 6 está correta, pois a MainActivity her-
da os atributos e métodos da classe AppCompatActivity.

2-12
(  ) -d) Não podemos sobrescrever o método onCreate, pois ele não
existe na classe AppCompatActivity.

EX ER C ÍC IO S PR O PO STO S
(  ) -e) Não podemos sobrescrever o método onCreate passando
como parâmetro o tipo Bundle?.

6) Considere o código abaixo e escolha a alternativa incorreta:

7|  
override fun onCreate(savedInstanceS-
tate: Bundle?) {
8|   super.onCreate(savedInstanceState)
9|   setContentView(R.layout.activity_main)
10|  }

(  ) -a) Precisamos sobrescrever o método, pois ele é executado as-


sim que o usuário abre o aplicativo.
(  ) -b) Na linha 9 utilizamos o método setContentView, para ins-
tanciar os elementos definidos no arquivo de layout activi-
ty_main.xml
(  ) -c) Podemos omitir a palavra-chave override da declaração do
método onCreate
(  ) -d) A referência para o arquivo activity_main fica armazenada
na constante R.layout.activity_main
(  ) -e) O parâmetro savedInstanceState é controlado automatica-
mente pelo Android para restaurar o estado da aplicação.

7) Escolha a afirmativa correta sobre o método onCreate

(  ) -a) Não podemos sobrescrever o método onCreate pois ele não


faz parte da classe MainActivity.
(  ) -b) O método onCreate é apenas chamado quando fechamos a
aplicação
(  ) -c) Para sobrescrevemos o método onCreate precisamos de in-
cluir mais um parâmetro além do savedInstanceState
(  ) -d) Não podemos chamar o método super.onCreate, pois a classe
mãe da MainActivity não possui este método implementado.

2-13
(  ) -e) Temos que sobrescrever o método onCreate pois ele é cha-
mado assim que o aplicativo é aberto, e é neste momento

EX ER C ÍC IO S PR O PO STO S
que iremos criar os elementos de layout.

8) Qual a utilidade do Gradle ?

(  ) -a) O Gradle é o compilador do Android.


(  ) -b) O Gradle é o gerenciador de construção e de bibliotecas do
projeto Android.
(  ) -c) O Gradle gerencia apenas a versão do Android do projeto.
(  ) -d) O Gradle precisa ser executado em linha de comando pois
não pode ser acessado pelo Android Studio.
(  ) -e) O Gradle apenas gerencia as bibliotecas do projeto, mas o
processo de build (construção) do aplicativo é feito interna-
mente pelo Android Studio.

9) Sobre o AVD escolha a afirmativa correta:

(  ) -a) O AVD é um gerenciador de versões do sistema operacional


Android que podem ser carregadas em um dispositivo real.
(  ) -b) A sigla AVD significa Android Virtual Device e é o simulador
da plataforma Android.
(  ) -c) A sigla AVD significa Android Virtual Device e é o emulador
da plataforma Android.
(  ) -d) O AVD não pode ser criado pelo Android Studio.
(  ) -e) É necessário pagar uma licença para utilizar o AVD.

10) Como podemos executar o projeto Android sem um dispositivo real?


(  ) -a) Não é possível executar o aplicativo Android sem um dispo-
sitivo real.
(  ) -b) Devemos criar um AVD ou seja um Android Virtual Device,
utilizando o gerenciador disponibilizado pelo kit de desen-
volvimento que vem junto com o Android Studio. E instalar
o executável do projeto pela linha de comando.
(  ) -c) Podemos usar o simulador do Android.

2-14
(  ) -d) No Android Studio, devemos criar um AVD, e depois clicar
no botão verde de play.

EX ER C ÍC IO S PR O PO STO S
(  ) -e) N.d.a

2-15
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 2:
INTRODUÇÃO A LINGUAGEM KOTLIN

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Na unidade 2 veremos os conceitos fundamentais da lingua-


gem Kotlin que são necessários para darmos os primeiros passos
no desenvolvimento de aplicativos móveis para o sistema opera-
cional Android.

Ótimos estudos!

Conteúdos da Unidade:
Declaração de variáveis, Tipos de variáveis, Variáveis imu-
táveis e mutáveis, Operadores aritméticos, Operadores de com-
paração, Expressões condicionais com if e else, Expressões
condicionais com when, Estruturas de repetição com while,
Estruturas de repetição com for.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 3:
VARIÁVEIS, TIPOS E OPERADORES
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


3.1 Introdução
Desde 2017 a linguagem oficial para desenvolvimento na
plataforma Android mudou de Java para Kotlin, mas a linguagem
Kotlin existe desde 2010.
Ao compararmos a linguagem Kotlin com a linguagem Java,
podemos dizer que a linguagem Kotlin possui uma sintaxe limpa e
expressiva, ponto e vírgula não são mais necessários, getters/
setters são opcionais, o que reduz em muito a verbosidade
do código.
Neste capítulo vamos introduzir os conceitos necessários
da linguagem Kotlin para que possamos, mais a frente, trabalhar
com as bibliotecas necessárias para o desenvolvimento de aplica-
tivos Android.
Nos próximos capítulos veremos vários exemplos escri-
tos na linguagem Kotlin, que servirão de apoio na compreensão
dos conceitos.
É muito interessante que o leitor possa digitar estes exem-
plos e fazer alguns experimentos, mudar algumas coisas e ver o que
acontece, para isso não precisamos do Android Studio, podemos
usar algumas ferramentas online que processam código Kotlin de
maneira muito rápida.
Uma destas ferramentas é a https://play.kotlinlang.org/, é
só acessar o site e escrever o código dentro da função main e clicar
no botão run. A saída do programa irá aparecer na parte inferior
da tela.

3-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


3.2 Declarando variáveis
Durante a programação de um aplicativo é muito comum
termos que armazenar, por exemplo, os dados que o usuário for-
nece em um campo texto, para que posteriormente algum cálculo
seja relacionado.
Utilizamos a ferramenta https://play.kotlinlang.org/, e en-
tramos com o código abaixo:

1| fun main() {
2|   var quantidade = 3
3|   var preco = 2.50
4|   var custoTotal = preco * quantidade
5|  println(custoTotal)
6| }

Na primeira linha, declaramos a função main, mais adian-


te você aprenderá como escrever funções, mas por hora lembre-se
apenas que todo o código dentro das chaves, ou seja todo o código
das linhas 2 até 4 será executado.
Vamos agora para a linha 2, veja que usamos a palavra-chave
var, é por meio desta palavra chave que definimos uma variável,
na sequência inserimos um espaço em branco e escrevemos o nome
dessa variável, neste caso chamamos de variável quantidade.
Logo após o nome da variável utilizamos o operador =, que
podemos chamar de operador de atribuição, pois estamos indi-
cando que queremos armazenar o valor inteiro 3 na variável cha-
mada quantidade.

3-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Note que na definição da variável quantidade, não deixa-
mos explícito o tipo da variável, isso acontece, pois a linguagem
Kotlin é capaz de fazer inferência de tipo, ou seja, ela é capaz de adi-
vinhar qual o tipo da variável baseando-se no valor de inicialização.
No caso da linha 2 a variável quantidade será do tipo Int,
pois o Kotlin considera o valor 3 como sendo do tipo Int.
Já na linha 3, novamente utilizamos a palavra-chave var e
definimos a variável preço, veja que agora, atribuímos a essa va-
riável o valor 2.5, ou seja, um valor não inteiro, neste caso a lin-
guagem Kotlin fará a inferência e o tipo de variável escolhido será
o Double. Atente para o fato de que, na linguagem Kotlin, casas
decimais são definidas usando o símbolo ponto, e não a vírgula,
pois a linguagem segue a notação do inglês.
Chegando na linha 4, definimos mais uma variável chamada
custoTotal, veja que nesta variável utilizamos o padrão camel-
Case, este é o padrão de escrita de código utilizado na linguagem
Kotlin, começamos com uma letra minúscula e na posição onde
teríamos o espaço, colocamos uma letra maiúscula e assim suces-
sivamente, pois não podemos ter espaços em branco no nome de
uma variável.
A variável custoTotal armazenará o valor da multiplica-
ção das duas variáveis preço e quantidade, para isso utiliza-
mos o operador * que é o operador de multiplicação na linguagem
Kotlin, mais a frente veremos todos operadores aritméticos defini-
dos nesta linguagem.
Novamente a linguagem Kotlin infere que o tipo da variável
custoTotal será Double, pois na expressão aritmética temos
um valor Double, e para que as informações das casas decimais
não sejam perdidas a inferência de tipo define a nova variável tam-
bém com valor Double.

3-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Por fim, utilizamos a função println, para exibir o valor da
variável custoTotal, a saída deste programa será então 7.5, pois
3 vezes 2.5 é igual a 7.5
Mas se por algum motivo tivermos que definir o tipo de uma
variável “manualmente”, isso também é possível, considere o códi-
go abaixo como exemplo.

1| fun main() {
2|   var quantidade = 3
3|  println(quantidade::class.simpleName)
4|   var preco = 2.50
5|  println(preco::class.simpleName)
6|   var desconto: Int = 1
7|  println(desconto::class.simpleName)
8|  
var custoTotal = preco * quantida-
de - desconto
9|  println(custoTotal::class.simpleName)
10|  println(custoTotal)
11| }

Este programa faz o mesmo que o anterior, porém agora te-


mos a definição da variável desconto, veja que utilizamos o sím-
bolo dois pontos, e após um espaço definimos o tipo da variável
como sendo Int, desta maneira estamos deixando explícito que o
tipo desta variável é Int.

3-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Depois na linha 8 apenas subtraímos o valor do desconto, e
neste caso o resultado do programa será 6.5 pois 3 vezes 2.5 menos
1 é igual 6.5.
Neste código também inserimos alguns comandos println,
veja que usamos como parâmetro na linha 3 a expressão quanti-
dade::class.simpleName, por hora, entenda que código mos-
tra o tipo da classe ou seja o retorno dessa linha será Int, pois a
linguagem Kotlin inferiu isso na linha 2.
Já na linha 5, a função println, irá mostrar na tela, o tipo
Double, pois neste caso o valor atribuído foi 2.5, e assim por diante
para as demais linhas, resultando na seguinte saída do programa.

Int
Double
Int
Double
6.5

3.3 Declarando variáveis imutáveis


Quando sabemos que o valor de uma variável não vai mudar,
devemos usar a palavra chave val, no lugar de var, isso faz com
que o Kotlin, otimize memória, pois não será necessário, alocar a
quantidade máxima para o tipo inferido.
É considerado uma boa prática no desenvolvimento de sof-
tware, sempre que possível, evitarmos o uso de um valor em
sua forma literal, portanto neste caso utilizamos constantes para

3-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


armazenar esses números. Veja o programa anterior reescrito uti-
lizando variáveis imutáveis:

1| fun main() {
2|   val quantidade = 3
3|   val preco = 2.50
4|   val custoTotal = preco * quantidade
5|  println(custoTotal)
6| }

Veja que mudamos a palavra chave var, para a palavra chave


val, o programa irá rodar como anteriormente a saída será o valor
7.5, porém agora o programa atende às boas práticas e consome
menos memória.
Vamos fazer uma experiência, tentaremos modificar a cons-
tante custoTotal na linha 5, para isso considere o código abaixo:

1| fun main() {
2|   val quantidade = 3
3|   val preco = 2.50
4|   val custoTotal = preco * quantidade
5|   custoTotal = custoTotal - 1
6|  println(custoTotal)
7| }

3-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Quando executamos este programa, um erro que mostrará
a mensagem: “Val cannot be assigned”, vai acontecer pois esta-
mos tentando, na linha 5, atribuir um novo valor a uma variá-
vel imutável.

3.4 Tipos numéricos


A linguagem Kotlin, possui os seguintes tipos numéricos

Tabela 3-1: Tipos Numéricos


Tipo Descrição
Armazena inteiros de até 8 bits com sinal, os valores podem ir de
Byte
-128 até 127.
Armazena inteiros de até 16 bits com sinal, os valores podem ir de
Short
-32768 até 32767.
Armazena inteiros de até 32 bits com sinal, os valores podem ir de
Int
-2,147,483,648 (231) até 2,147,483,647 (231- 1).
Armazena inteiros de até 64 bits com sinal os valores pode ir de
Long -9,223,372,036,854,775,808(261) até 9,223,372,036,854,775,807
(261- 1).
Float Ocupa 32 bits e armazena números com casas decimais.
Double Ocupa 64 bits e armazena números com casas decimais.

3-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


3.5 O tipo String
O tipo String é muito utilizado e serve para armazenar os
valores do tipo texto, veja sua utilização no código abaixo:

1| fun main() {
2|   val nome = “Roberto”
3|   val sobreNome = “Morais”
4|   println(“Bem vindo $nome $sobreNome”)
5| }

Na linha 2 definimos a variável nome atribuído como valor a


literal o texto “Roberto”, na linha 3 definimos a variável sobreNo-
me, atribuindo o valor “Morais”. A linguagem Kotlin entende que o
texto entre aspas duplas é uma String e por isso infere que o tipo
de ambas as variáveis nome e sobreNome será String.
Por fim na linha 4 usamos a função println, note que usa-
mos o operador $, para fazer a interpolação com as duas variáveis
definidas anteriormente, podemos chamar o operador $ de inter-
polador, pois ele irá inserir o conteúdo das strings definidas nos
lugares marcados no parâmetro da função println.
Quando rodamos este programa teremos como resposta a
seguinte saída:

Bem vindo Roberto Morais

3-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


3.6 O tipo Boolean
É muito comum na programação termos que tratar situações
que possuem dois estados, como ligado ou desligado, visível ou in-
visível, conectado ou desconectado entre outros, para isso existe o
tipo Boolean, que define uma variável que pode receber apenas
dois valores chamados True ou False, respectivamente em por-
tuguês significam verdadeiro ou falso.
O exemplo abaixo mostra a declaração de duas variáveis do
tipo Boolean:

1| fun main() {
2|   val ligado = true
3|   val conectado = false
4|  println(ligado::class.simpleName)
5|  println(ligado)
6|  println(conectado)
7| }

Na linha 2 definimos a variável imutável chamada ligado,


e atribuímos o valor true, isso faz com que a linguagem Kotlin
infira que o tipo desta variável será Boolean.
Da mesma maneira na linha 3 definimos a variável imutá-
vel chamada conectado, e atribuímos o valor false, o que fará
com que a linguagem Kotlin defina o tipo desta variável como
sendo Boolean.
Para confirmar que o tipo da variável ligado é Boolean, usa-
mos o código da linha 4 e o valor mostrado na tela será Boolean,

3-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


na sequência mostramos os valores das variáveis ligado e conecta-
do, ambas serão true e false respectivamente, portanto a saída
do programa acima será:

Boolean
true
false

3.7 Operadores aritméticos


Os operadores aritméticos da linguagem Kotlin são respon-
sáveis por realizar operações matemáticas básicas com valores lite-
rais ou valores armazenados em variáveis e em variáveis imutáveis,
a tabela abaixo relaciona os operadores aritméticos da linguagem:

Tabela 3-2: Operadores aritméticos


Símbolo Descrição
+ Operador de soma
- Operador de subtração
* Operador de multiplicação
/ Operador de divisão
% Operador de resto

Veja o código abaixo, que demonstra o uso dos operadores


descritos na tabela acima:

1| fun main() {
2|

3-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


3|   val x = 5
4|   val y = 2
5|
6|   val soma = x + y
7|   val subtracao = x - y
8|   val multiplicacao = x * y
9|   val divisaoInteira = x / y
10|   val restoDaDivisao = x % y
11|
12|   println(“Soma $soma”)
13|   println(“Subtração $subtracao”)
14|   println(“Multiplicação $multiplicacao”)
15|   println(“Divisão inteira $divisaoInteira”)
16|   println(“Resto da divisão $restoDaDivisao”)
17| }

Nas linhas 3 e 4 definimos duas variáveis imutáveis, uma de-


las chamada x e a outra chamada y, na linha 6 utilizamos o opera-
dor de soma e armazenamos na variável soma o valor resultante da
operação, que será 7.
Na sequência, efetuamos a subtração das duas variáveis,
utilizando o operador menos, fazendo 5 - 2, o que resultará no
valor 3, que será armazenado na variável imutável cha-
mada subtração.

3-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Logo na linha 8 utilizamos o operador de multiplicação *,
efetuando a operação 2 vezes 5 resultando no valor 10, que será
armazenado na variável imutável multiplicação.
Fazemos o mesmo para o operador de divisão, veja que como
ambas as variáveis x e y são do tipo Int, a divisão será inteira ou
seja o valor 2 será o resultado da divisão, e será armazenado na
variável imutável de nome divisaoInteira.
Por fim utilizamos o operador de resto da divisão, para cal-
cular o valor do resto da divisão inteira de 5 por 2, ou seja, este va-
lor será 1. Após a execução do programa teremos a seguinte saída
na tela:

Soma 7
Subtração 3
Multiplicação 10
Divisão inteira 2
Resto da divisão 1

3.8 Operadores de comparação


Durante o desenvolvimento de um aplicativo, é muito prová-
vel que tenhamos que comparar algum valor, suponha um aplica-
tivo que dirá se o aluno foi aprovado numa determinada matéria
onde a média de aprovação é 5, neste caso deveremos comparar se
a nota do aluno é maior que a média ou não.
Para isso existem os operadores de comparação, atente ao
fato de que o resultado de uma operação de comparação é um
valor Booleano, pois uma comparação pode retornar apenas 2

3-14
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


valores, verdadeiro ou falso. A tabela abaixo relaciona os operado-
res de comparação.

Tabela 3-3: Operadores de comparação


Operador Descrição
Este operador compara se o operando da direita é igual ao
== operando da esquerda, retornando true se isso for verdade ou
false caso contrário.
Este operador verifica se o operando da direita é diferente do
!= operando da esquerda, se isso for verdade o resultado da ope-
ração será true, caso contrário será false.
Este operador compara se o operando da esquerda é maior
> que o operando da direita, se isso for verdade então a operação
retorna true, caso contrário retorna false.
Este operador compara se o operando da esquerda é menor que
< o operando da direita, se esse for o caso então o valor retorna-
do pela expressão será true, caso contrário será false.
Este operador compara se o operando da esquerda é maior ou
>= igual ao operando da direita, se isso for verdade então a opera-
ção retornará o valor true caso contrário retornará false.
Este operador compara se o operando da esquerda é menor ou
<= igual operando da direita, se esse for o caso então o resultado
da operação será o valor true, caso contrário será o valor false.

O código abaixo, mostra o caso de uso de alguns operadores


descritos na tabela acima:

1| fun main() {
2|   var comparacao = 3 == 3
3|   println(“3 é igual a 3 ? $comparacao”)
4|   comparacao = 3 != 3

3-15
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


5|   println(“3 é diferente de 3 ? $comparacao”)
6|   comparacao = 3 > 5
7|   println(“3 é maior que 5 ? $comparacao”)
8|   comparacao = 3 < 8
9|   println(“3 é menor que 8 ? $comparacao”)
10|   comparacao = 3 >= 3
11|  
println(“3 é maior ou igual a 3
? $comparacao”)
12| }

Na linha 2, definimos a variável comparação, e atribuímos


a ela o valor da expressão 3 == 3, veja que utilizamos o operador
==, que compara se o valor 3 é igual a 3, neste caso o valor
armazenado na variável comparação será true, pois 3 é igual a 3.
Na sequência na linha 4 fizemos a comparação oposta, ou
seja, estamos calculando o resultado da expressão 3 != 3, lem-
brando que o operador != verifica se ambos os operandos são di-
ferentes, então neste caso o valor armazenado na variável compa-
ração será false, pois 3 é igual a 3.
Agora chegou a vez do operador >, maior que, veja que 3
não é maior que 5 ou seja, o valor armazenado na variável
comparação na linha 6 será false.
Vamos agora usar o operador <, menor que, neste caso o ope-
rando da esquerda que é o 3 é menor que o operando da
direita que é o 8, ou seja, o resultado desta expressão é
true, e isso é armazenado na variável comparação na linha 8.
Por fim utilizamos o operador >=, maior ou igual, neste caso
o operando da esquerda é o valor 3 e o operando da direita também

3-16
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


é o valor 3, ou seja, ambos são iguais, como esse operador testa se
os operandos são maiores ou iguais, o valor retornado pela
expressão será true, pois 3 é igual a 3.
Ao executarmos o programa, teremos a saída abaixo, confor-
me o que foi descrito:

3 é igual a 3 ? true
3 é diferente de 3 ? false
3 é maior que 5 ? false
3 é menor que 8 ? true
3 é maior ou igual a 3 ? true

3.9 Operadores lógicos


Por meio dos operadores lógicos podemos construir expres-
sões onde os operandos são do tipo Boolean, veja abaixo os ope-
radores e o que cada um realiza numa expressão lógica. Para isso
vamos utilizar uma ferramenta muito útil que chamamos de ta-
bela verdade.
Por meio da tabela verdade escrevemos todos os possíveis
resultados entre dois operandos e os operadores lógicos, vamos co-
meçar pelo operador, ou seja, podemos chamar este operador de e.

Tabela 3-4: Tabela verdade operador &&


Operando 1 Operando 2 Resultado
true True true
false True false

3-17
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Operando 1 Operando 2 Resultado
true False false
false False false

Segundo a tabela acima, o operador && apenas retornará o


valor true quando o valor de ambos operandos forem true, para
todos os outros casos o valor retornado será false.
Veremos agora a tabela verdade para o operador ||, chama-
mos esse operador de ou:

Tabela 3-5: Tabela verdade operador ||


Operando 1 Operando 2 Resultado
true true true
false true true
true false true
false false false

No caso do operador || ou, o resultado será false apenas


se ambos os valores dos operandos forem iguais a false, para to-
dos os outros casos o valor retornado pela operação será true.
Por fim vamos para a tabela do operador !, ou seja, o opera-
dor não, este operador tem uma particularidade, podemos chamá-
-lo de operador unário pois ele precisa de apenas um operando:

Tabela 3-6: Tabela verdade operador !


Operando Resultado
true False
false True

Veja o código abaixo, que mostra o uso dos operadores lógicos:

3-18
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


1| fun main() {
2|   var senhaValida = false
3|   var usuarioValido = false
4|  
var acessoLiberado = senhaValida
&& usuarioValido
5|   println(“Acesso liberado $acessoLiberado”)
6|   senhaValida = true
7|   usuarioValido = false
8|   acessoLiberado = senhaValida && usuarioValido
9|   println(“Acesso liberado $acessoLiberado”)
10|   senhaValida = false
11|   usuarioValido = true
acessoLiberado = senhaValida && usuarioValido
12|  
13|   println(“Acesso liberado $acessoLiberado”)
14|   senhaValida = true
15|   usuarioValido = true
16|   acessoLiberado = senhaValida && usuarioValido
17|   println(“Acesso liberado $acessoLiberado”)
18| }

Vamos considerar o caso a variável acessoLiberado, só


terá o valor true se ambas as variáveis senhaValida usuario-
Valido possuírem o valor true. Para isso utilizaremos o opera-
dor &&, pois veja que na tabela verdade deste operador o resultado
retornado apenas será true se ambos os valores dos operandos
for true.

3-19
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 3

VA R IÁV EIS , TIP O S E O PER AD O R ES


Nas linhas 2 e 3 definimos ambas as variáveis acessoLibe-
rado e senhaValida, com o valor false. Em seguida na linha
4 efetuamos a operação senhaValida && usuarioValido,
armazenando na variável acessoLiberado o valor false, pois
neste caso ambas as variáveis possuem o valor false.
Na sequência mostramos na tela o valor da variável aces-
soLiberado, mostrando que ele é false.
Agora vamos mudar o valor da variável senhaValida, para
true simulando que o usuário entrou com a senha correta, porém
o valor da variável usuarioValido, continuará sendo false,
desta maneira nossa simulação dirá que a variável acessoLibe-
rado ainda possui o valor false.
Desta vez vamos simular a situação onde o usuário entrou
com a senha incorreta, ou seja, o valor da variável senhaValida,
será false, porém neste caso, o usuário entrou com a sua identi-
ficação correta, ou seja, o valor da variável usuarioValido ago-
ra é true.
Ainda sim neste caso a variável acessoLiberado deverá
possuir valor false, pois uma das informações está errada, e pelo
operador && é exatamente isso que acontece, pois um dos operan-
dos possui o valor false.
Agora vamos ao caso onde ambas as variáveis possuem o va-
lor true, neste caso simulamos a situação onde o usuário entrou
corretamente com os valores da senha e da sua identificação, neste
caso a expressão senhaValida && usuarioValido, irá retor-
nar o valor true.

3-20
 EXERCÍCIOS PROPOSTOS

1) O que é uma variável ?

(  ) -a) Um elemento no código que não podemos prever o valor


(  ) -b) Um elemento no código que não sabemos qual é o tipo
(  ) -c) Um espaço alocado em memória RAM baseado em um tipo
específico utilizado para armazenar valores que podem
variar.
(  ) -d) Um elemento no código que quando inicializado com um va-
lor específico nunca mais poderá ter esse valor modificado.
(  ) -e) Um espaço alocado em memória de disco baseado em um
tipo específico utilizado para armazenar valores que podem
variar.

2) Qual a diferença entre val e var ?

(  ) -a) Quando definimos uma variável com var sabemos que o seu
valor vai mudar, quando definimos uma variável com val sa-
bemos que o seu valor não vai mudar, ou seja estamos defi-
nindo uma variável imutável.
(  ) -b) Quando definimos uma variável com val sabemos que o seu
valor vai mudar, quando definimos uma variável com var
sabemos que o seu valor não vai mudar, ou seja, estamos
definindo uma variável imutável.
(  ) -c) Não existe diferença entre o uso das duas palavras chaves
val e var.
(  ) -d) Quando definimos uma variável com val sabemos que o seu
tipo vai mudar, quando definimos uma variável com var sa-
bemos que o seu tipo não vai mudar, ou seja estamos defi-
nindo uma variável imutável.
(  ) -e) N.d.a.

3-21
3) Quando devemos usar o tipo Byte ?

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Para armazenar valores monetários que usam apenas duas
casas decimais.
(  ) -b) Para armazenar valores inteiros da ordem de grandeza dos
milhares.
(  ) -c) Para armazenar valores que representam medidas de com-
primento com até 4 casas decimais.
(  ) -d) Para armazenar o número de alunos em uma sala de aula,
suponho que esse número não seja maior que 30.
(  ) -e) Para armazenar o número de moléculas em um composto
orgânico.

4) Quando devemos usar o tipo Double ?

(  ) -a) Para armazenar o número de moléculas em um composto


orgânico.
(  ) -b) Para armazenar o valor da constante Pi com o máximo de
casas decimais que a linguagem Kotlin permite.
(  ) -c) Para armazenar os valores de um sensor de temperatura de
ambiente.
(  ) -d) Para armazenar valores inteiros que representam as popu-
lações de países.
(  ) -e) N.d.a.

5) Quando devemos usar o tipo String?

(  ) -a) Para representar uma situação onde podemos ter dois esta-
dos, verdadeiro ou falso.
(  ) -b) Armazenar os valores numéricos de 1 até 10.
(  ) -c) Quando temos que armazenar o nome de um usuário.
(  ) -d) Armazenar os valores da constante Pi com o máximo de ca-
sas decimais.
(  ) -e) Armazenar valores monetários para realizar o cálculo do im-
posto devido.

3-22
6) Quando devemos usar uma variável do tipo Boolean?

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Quando temos uma situação onde o resultado será apenas
0 ou 1.
(  ) -b) Quando queremos armazenar o resultado de uma operação
lógica.
(  ) -c) Quando temos uma situação, onde teremos apenas os valo-
res em texto “verdadeiro” ou “falso”.
(  ) -d) Quando temos uma situação onde queremos armazenar o
texto que representa as unidades celsius “°C” ou fahrenheit
“°F”
(  ) -e) N.d.a

7) Considere o código abaixo que utiliza o operador % e escolha a alterna-


tiva correta

1| fun main() {
2|   val x = 9
3|   val y = 7
4|   val resultado = x % y
5|   println(“Resultado $resultado”)
6| }

(  ) -a) O resultado mostrado na tela será 1, ou seja, o valor da divi-


são inteira do valor 9 pelo valor 7.
(  ) -b) O resultado mostrado na tela será o valor de 9% de 7, ou
seja, 0.63.
(  ) -c) O resultado mostrado será o valor da divisão com duas casas
de decimais de 9 / 7 ou seja 1.28
(  ) -d) O resultado será 2 pois o operador % retorna o resto da divi-
são inteira de 9 / 7.
(  ) -e) O resultado será 0 pois o resto da divisão entre x e y é 0.

3-23
8) Considere o código abaixo que utiliza os operadores de comparação e

EX ER C ÍC IO S PR O PO STO S
escolha a alternativa correta.

1| fun main() {
2|   val resultado1 = 9 <= 7
3|   val resultado2 = 5 >= 5
4|   val resultado3 = 7 > 7
5|   println(“Resultado1 $resultado1”)
6|   println(“Resultado2 $resultado2”)
7|   println(“Resultado3 $resultado3”)
8| }

(  ) -a) O programa vai retornar um erro pois não podemos armaze-


nar o resultado de uma operação relacional.
(  ) -b) O programa vai retornar um erro pois as variáveis imutáveis
definidas nas linhas 2, 3 e 4 não foram definidas com o tipo
correto.
(  ) -c) O tipo das variáveis resultado1, resultado2 e resultado 3 é
Int.
(  ) -d) O programa irá mostrar na tela os valores true, false e true.
(  ) -e) O programa irá mostrar na tela os valores false, true e false.

9) Considere o código abaixo que utiliza os operadores lógicos && e || e


escolha a alternativa correta.

1| fun main() {
2|   val x1 = true
3|   val x2 = false
4|   val x3 = true
5|   val x4 = true
6|   val resultado1 = (x1 && x2) || (x3 && x4)
7|   val resultado2 = x1 || x2 || x3
8|   val resultado3 = x1 && x2 && x3 && x4
9|   val resultado4 = x1 || x4 || x3 && x2

3-24
10|  val resultado5 = (x1 && x2 && x3) ||
(x1 || x4)

EX ER C ÍC IO S PR O PO STO S
11| println(“$resultado1,
12|       $resultado2,
13|       $resultado3,
14|       $resultado4,
15|       $resultado5”)
16| }

(  ) -a) False, false, false, false, false


(  ) -b) True, true, false, true, true
(  ) -c) False, true, false, true, false
(  ) -d) True, true, false, false, true
(  ) -e) True, true, true, true, true

10) Considere o código abaixo que utiliza os operadores de lógicos e de com-


paração e escolha a alternativa correta.

1| fun main() {
2|   val x1 = false
3|   val x2 = 10 <= 10
4|   val x3 = 1 > 2
5|   val x4 = 7 != 7
6|   val resultado1 = (x1 && x2) || (x3 && x4)
7|   val resultado2 = x1 || x2 || x3
8|   val resultado3 = x1 && x2 && x3 && x4
9|   val resultado4 = x1 || x4 || x3 && x2
10|   val resultado5 = (x1 && x2 && x3) ||
(x1 || x4)
11|  println(“$resultado1,
12|        $resultado2,
13|        $resultado3,
14|        $resultado4,
15|        $resultado5”)
16| }

3-25
(  ) -a) False, true, false, false, false
(  ) -b) True, true, false, false, true

EX ER C ÍC IO S PR O PO STO S
(  ) -c) False, false, false, false, false
(  ) -d) True, true, true, true, true
(  ) -e) False, false, true, true, false

3-26
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 4:
CONTROLE DE FLUXO
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
4.1 Introdução
Toda linguagem de programação possui estruturas que con-
trolam o fluxo do programa. As estruturas de repetição são respon-
sáveis por fazer com que um determinado bloco de código se repita
até que uma condição seja ou satisfeita.
Fazem parte deste grupo as estruturas declaradas com as
palavras chaves while e for. É muito comum chamarmos essas
estruturas de laços de repetição.
A outra categoria de estruturas de controle de fluxo são as
expressões condicionais, estas estruturas executam um determi-
nado bloco de código se uma condição for satisfeita, fazem parte
destas estruturas as que são declaradas pelas palavras chaves if,
else e when.

4.2 Expressões condicionais com if e else


Imagine a situação onde queremos fazer um programa que
diz ao usuário se ele foi aprovado numa determinada disciplina
onde a média de aprovação é 5, ou seja, caso a média do usuário
seja superior ou igual a 5 o programa irá mostrar uma mensagem
dizendo que o usuário foi aprovado, caso contrário, ou seja a média
do usuário foi inferior a 5 o programa irá mostrar uma mensagem
dizendo ao usuário que ele não foi aprovado.
Para construir esse programa precisaremos usar uma expres-
são condicional utilizando a palavra-chave if e a palavra-chave
else, veja abaixo, de maneira genérica, como construir uma ex-
pressão condicional na linguagem Kotlin:

1| if (expressão lógica) {

4-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
2|  
bloco de código executado quando o re-
sultado da expressão lógica for true
3| } else {
4|  
bloco de código executado quando o re-
sultado da expressão lógica for false
5| }

Quando a expressão lógica, entre os parênteses da palavra-


-chave if retornar o valor true, o bloco de código entre as chaves
será executado.
Caso contrário, se a expressão lógica entre os parênteses da
palavra-chave if retornar o valor false, o bloco de código das
chaves do else, será executado.
Usando a forma genérica com guia, vamos construir o pro-
grama que resolve o problema da média exposto no começo
deste capítulo.

1| fun main() {
2|   val media = 3.0
3|   if (media >= 5.0) {
4|   println(“O aluno foi aprovado na matéria”)
5|   } else {
6|   println(“O aluno foi reprovado na matéria”)
7|  }
8| }

4-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
Começamos o programa definindo a variável imutável media
com valor 3.0, esta variável vai armazenar a média na disciplina
que o usuário possui.
Na sequência, na linha 3 utilizamos a palavra-chave if, e
dentro dos parênteses escrevemos a expressão condicional media
>= 5.0, veja que utilizamos o operador de comparação maior ou
igual e como operandos a variável media, e o valor 5.0, ou seja,
sempre que a variável média possuir valor maior que 5.0 está ex-
pressão lógica irá retornar o valor true, caso contrário, se o valor
da variável média for menor que 5.0 então a expressão lógica irá
retornar false.
No caso deste programa, sabemos que o valor da variável
imutável é 3, ou seja 3 é menor que 5, logo o valor da expressão
media >= 5.0, vai ser false e como dito anteriormente, neste
caso o bloco de código dentro das chaves após a palavra else vai
ser executado e a mensagem informando que o usuário foi repro-
vado irá aparecer na tela.
Agora reescreva o código de modo que o valor da variável
media seja 7.5, neste caso a expressão condicional media >=
5.0, retornará o valor true, fazendo com que o bloco de código
das chaves que seguem a expressão condicional seja executado e
portanto neste caso, uma mensagem informando que o usuário foi
aprovado, irá ser exibida na tela.
Faça mais alguns experimentos com esse código, mude o va-
lor para 5.0, e para outros valores até que você se familiarize com
essa estrutura.
Atente para o fato de que a estrutura else é opcional, con-
sidere o programa abaixo que mostra uma mensagem quando o
número armazenado na variável numeroA for maior que o número
armazenado na variável numeroB.

4-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
1| fun main() {
2|   val numeroA = 30
3|   val numeroB = 17
4|
5|   if (numeroA > numeroB) {
6|   
println(“Número $numeroA é maior
que $numeroB”)
7|  }
8| }

Nas linhas 2 e 3 definimos respectivamente as variáveis imu-


táveis numeroA com valor 30 e numeroB com valor 17. Logo na
linha 5 construímos a estrutura condicional baseada na expressão
lógica numeroA > numberoB, note que usamos o operador maior
que, neste caso esta expressão lógica irá retornar o valor true se o
valor da variável numeroA, for maior que o valor da variável nu-
meroB, e como o valor da variável numeroA é 30 e o valor da variá-
vel numeroB é 17 então a expressão lógica numeroA > numberoB
retornará o valor true, e o bloco de código definido na linha 6 será
executado e a mensagem informando que o número 30 é maior que
o número 17 será exibida na tela.
Veja que como não temos uma implementação para o else,
então se o valor da variável numeroA for menor que o valor da va-
riável numeroB nada será mostrado na tela.
Podemos também escrever estruturas condicionais usando a
palavra-chave else if, veja abaixo um exemplo de como pode-
mos fazer isso:

4-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
1| fun main() {
2|   val tipoCafe = 3
3|   if (tipoCafe == 1) {
4|   println(“Café Latte”)
5|   } else if (tipoCafe == 2) {
6|   println(“Expresso”)
7|   } else if (tipoCafe == 3) {
8|   println(“Café Coado”)
9|   } else {
10|    println(“Opção não encontrada”)
11|  }
12| }

Iniciamos declarando a variável imutável chamada tipo-


Cafe com o valor 3, logo abaixo na linha 3, utilizamos a palavra
chave if para verificar se o valor da variável tipoCade é igual a
1, como o resultado desta operação retorna o valor False, a men-
sagem da linha 4 não será mostrada na tela, pois a linha 4 não
será executada.
O fluxo do programa será então desviado para a linha 5, e
agora a expressão else if, vai checar se o valor da variável ti-
poCafe é igual a 2, e novamente o resultado da expressão lógica
será o valor False. Ou seja, a linha 6 não será executada e o fluxo
do programa será desviado para a linha 7, onde novamente utiliza-
mos a expressão else if, porém agora, como o valor da variável
tipoCafe é igual a 3 a linha 8 será executada e a mensagem: Café
Coado vai aparecer na tela.

4-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
Note que a linha 10 não será executada pois o fluxo do pro-
grama saiu do bloco condicional pela linha 10.
Caso o valor da variável tipoCafe, não fosse 1, 2 ou 3 então
apenas nesse caso a linha 10 seria executada.

4.3 Expressões condicionais com when


Outra maneira de escrevermos expressões condicionais em
Kotlin é usando a palavra-chave when, considere o código abaixo
como exemplo:

1| fun main() {
2|
3|   val x = 5
4|
5|   when (x) {
6|    1 -> println(“X possui o valor 1”)
7|    2 -> println(“X possui o valor 2”)
8|    5 -> println(“X possui o valor 5”)
9|    else -> {
10|    println(“X possui qualquer outro valor”)
11|   }
12|  }
13| }

4-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
Começamos declarando a variável imutável x com valor igual
a 5, e logo na linha 5 utilizamos a palavra-chave when, para marcar
a estrutura condicional, note que queremos testar qual é o valor da
variável x, neste caso ela foi incluída entre os parênteses logo na
sequência da palavra-chave when.
Após declarada a variável que será testada pela expressão
condicional when abrimos a chave e na linha 6 verificamos se o
valor da variável é igual a 1, caso for o código na frente da marca ->
será executado.
O mesmo é verdade para as linhas 7 e 8, note que o valor da
variável x é 5, portanto o código que será executado está na linha
8, fazendo com que a mensagem informando que x possui o valor
5 será exibida.
Nessa estrutura podemos também utilizar a palavra-cha-
ve else, com o objetivo de desviar o fluxo do programa para o
código entre as chaves do else, caso nenhuma condição acima
seja satisfeita.
Aproveite para mudar o valor da variável x e fazer algumas
experiências com o código do when, por exemplo mudando seu va-
lor para 10 ou mesmo para 2.

4.4 Estrutura de repetição com while


Imagine que precisamos construir um programa que mostre
na tela os números e 1 até 1000, será que teremos que escrever
1000 linhas de código para isso? A resposta é não, pois neste caso
devemos usar uma estrutura de repetição, veja abaixo a forma ge-
nérica de uma estrutura de repetição utilizando a instrução while.

4-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
1| while (expressão lógica) {
2|  bloco de código que será repetido enquanto
a expressão lógica retornar o valor true
3| }

O modelo genérico descrito acima diz que enquanto a ex-


pressão lógica entre os parênteses da palavra-chave while
retornar o valor true então todo o bloco de código escrito entre
chaves será executado.
Vamos retomar o problema da contagem até 1000, vamos es-
crever o código que faz isso utilizando a expressão while.

1| fun main() {
2|   var x = 1
3|   while (x <= 1000) {
4|   println(x)
5|    x = x + 1
6|  }
7| }

Já na linha 2 declaramos a variável chamada x, veja que usa-


mos a palavra-chave var ao invés da palavra chave val, fizemos
isso pois o valor da variável x vai ser modificado, na linha 3 escre-
vemos a palavra-chave while e na sequência entre os parênteses
colocamos a expressão lógica que vai controlar a estrutura de re-
petição, veja que como queremos mostrar na tela os números de
1 até 1000, construímos uma expressão lógica que verifica se x é
menor ou igual a 1000, ou seja, quando o valor de x for 1001 o

4-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
fluxo do programa não vai executar o bloco de código definido nas
linhas 4 e 5.
Como inicializamos a variável chamada x com o valor 1, da
primeira vez a expressão lógica x <= 1000, retornará o valor
true, e as linhas 4 e 5 serão executadas, na linha 4 uma mensagem
será mostrada com valor da variável que neste primeiro caso será
1 e na linha 5 incrementamos este valor somando 1, ou seja, após a
execução da linha 5 o valor da variável x mudará para 2.
O valor 2 é menor do que 1000, portanto a expressão lógica
x <= 1000 retornará o valor true, ou seja, novamente as linhas
4 e 5 serão executadas, portanto o valor 2 será mostrado na tela e a
variável x será incrementada em 1, e ao fim da execução da linha 5
esta variável possuirá o valor 3.
Vamos avançar no tempo, e assumir que a variável x chegou
ao valor 1000, neste caso a condição x <= 1000, ainda será válida
e as linhas 4 e 5 serão executadas, portanto o valor 1000 será mos-
trado na tela e na linha 5 o valor da variável x que agora é de 1000,
será incrementado em 1, ou seja, o valor da variável x agora é 1001.
Veja que agora a expressão x <= 1000, é inválida, pois x é
igual a 1001 e 1001 é maior que 1000, portanto esta expressão irá
retornar false e a estrutura de repetição não irá mais executar
as linhas 4 e 5, consequentemente o programa vai terminar e os
números de 1 até 1000 foram mostrados na tela como queríamos.

4.5 Estrutura de repetição com for


Além da instrução while podemos usar utilizar a instru-
ção for para construir laços de repetição, veja no exemplo abaixo

4-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 4

C O N TR O LE D E FLU XO
como utilizar a instrução for para fazer o laço de repetição que re-
solve o problema de mostrar todos os números de 1 até 1000 na tela

1| fun main() {
2|   for (x in 1..1000) {
3|   println(x)
4|  }
5| }

Já na linha 2 utilizamos a palavra chave for e dentro dos


parênteses definimos uma variável chamada x e usamos a palavra
chave in e o intervalo definido por 1.1000, ou seja, com esta nota-
ção estamos criando uma estrutura de repetição que vai fazer com
que x possua todos os valores entre 1 e 1000 inclusive.
Esta estrutura de repetição irá executar o código da linha 3,
1000 vezes, ou seja, os valores de 1 até 1000 serão mostrados na
tela. A instrução for é indicada quando queremos percorrer itens
em uma lista, veremos o conceito de lista nos próximos capítulos.

4-11
 EXERCÍCIOS PROPOSTOS

1) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   val temperatura = 28
3|   if (temperatura > 24) {
4|   println(“Baixar Temperatura”)
5|  }
6| }

(  ) -a) O código acima está errado pois não podemos usar os parên-
teses na linha 3.
(  ) -b) O código acima está errado pois a variável temperatura foi
declarada sem um tipo.
(  ) -c) O tipo da variável temperatura é Double.
(  ) -d) O código está correto e como resultado mostrará a mensa-
gem: Baixar Temperatura.
(  ) -e) O comando if, na linha 3 vai gerar um erro, pois este coman-
do não está definido na linguagem Kotlin.

2) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   val opcao = 2
3|   if (opcao == 1) {
4|   println(“Sabor morango”)
5|   } else if (opcao == 2) {
6|   println(“Sabor chocolate”)
7|   } else if (opcao == 3) {

4-12
8|   println(“Sabor limão”)
9|   } else {

EX ER C ÍC IO S PR O PO STO S
10|    println(“Sabor não encontrado”)
11|  }
12| }

(  ) -a) O código acima não compila, pois não podemos escrever a


instrução else if, apenas else.
(  ) -b) Como o valor da variável opcao é igual a 2 já na linha 3 a
expressão condicional vai retornar o valor False, e o fluxo do
programa será desviado para a linha 10, portanto será mos-
trado na tela a frase: Sabor não encontrado.
(  ) -c) A variável da linha 2 chamada opção foi declarada errada,
pois o tipo Int não foi especificado.
(  ) -d) Aparecerá na tela, depois da execução do programa a frase:
Sabor limão.
(  ) -e) Como o valor da variável opção é 2, a primeira expressão
condicional da linha 3 vai retornar False, e o fluxo será redi-
recionado para a linha 5, neste caso esta expressão condicio-
nal vai retornar True e portanto a mensagem mostrada na
tela será: Sabor chocolate

3) Escolha a afirmativa correta sobre a palavra-chave while na linguagem


Kotlin:

(  ) -a) A palavra-chave while, não está definida na linguagem Kotlin.


(  ) -b) A palavra-chave while, seguida de uma expressão lógica vai
executar a próxima linha uma única vez apenas se o valor
retornado pela expressão lógica for True.
(  ) -c) A palavra-chave while, seguida de uma expressão lógica vai
executar a próxima linha uma única vez apenas se o valor
retornado pela expressão lógica for False.
(  ) -d) A palavra-chave while, seguida de uma expressão lógica vai
executar o código definido entre chaves enquanto o resulta-
do da expressão lógica for igual a True.
(  ) -e) A palavra-chave while, seguida de uma expressão lógica vai
executar o código definido entre chaves enquanto o resulta-
do da expressão lógica for igual a False.

4-13
4) Escolha a afirmativa correta sobre as palavras chave if e else na lingua-

EX ER C ÍC IO S PR O PO STO S
gem Kotlin:

(  ) -a) Podemos omitir os parênteses na definição da expressão ló-


gica da palavra-chave if.
(  ) -b) Sempre que escrevermos uma expressão com a palavra-cha-
ve if somos obrigados a usar a palavra-chave else.
(  ) -c) Se a expressão lógica que segue a palavra-chave if, retornar o
valor True, então o código que estiver definido entre as cha-
ves logo abaixo da expressão lógica será executado.
(  ) -d) Se a expressão lógica que segue a palavra-chave if, retornar o
valor True, então o código que estiver definido entre as cha-
ves logo abaixo da expressão else será executado.
(  ) -e) Todo código definido entre chaves logo abaixo da palavra
chave else, sempre será executado.

5) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   var x = 1
3|   while ( x < 20 ) {
4|    if (x == 10) {
5|    println(“Uma dezena”)
6|    } else {
7|    println(x)
8|   }
9|    x = x + 1
10|  }
11| }

(  ) -a) Podemos declarar a variável x na linha 2 como sendo val.


(  ) -b) Nada será mostrado na tela pois as linhas 4 até 9 só serão
executadas se x for maior que 20, porém x é igual a 1.
(  ) -c) Todas as linhas de 4 até 9 serão executadas 20 vezes.
(  ) -d) O programa vai mostrar na tela os números de 1 até 19.

4-14
(  ) -e) O programa vai mostrar na tela os valores de 1 até 19 porém
no valor 10 será mostrada a mensagem: Uma dezena.

EX ER C ÍC IO S PR O PO STO S
6) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   var x = 1
3|   while ( x <= 5 ) {
4|   println(x)
5|  }
6| }

(  ) -a) O código acima exibe na tela os números de 1 até 5 e pode-


mos mudar a variável mutável x para ser uma variável imu-
tável utilizando a palavra-chave val, que o resultado será o
mesmo.
(  ) -b) A linha 4 do código acima nunca será executada pois a ex-
pressão lógica que controla a repetição só será válida se x for
maior que 5, porém como o valor de x é 1 a condição nunca
irá retornar o valor True.
(  ) -c) O código acima vai se repetir infinitas vezes pois o valor da
variável x nunca muda, ou seja, será 1 sempre, fazendo com
que a expressão da estrutura de repetição sempre retorne o
valor True, de maneira a nunca terminar o laço de repetição.
(  ) -d) Na linha 4 teremos um erro, pois não podemos usar uma
variável do tipo Int como parâmetro para a função println,
pois essa função apenas recebe como parâmetro valores do
tipo String.
(  ) -e) Na linha 2 a variável x foi declarada de maneira errada pois
o tipo da variável foi omitido.

7) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   var total = 0

4-15
3|   for (x in 1..5) {
4|    total = total + x

EX ER C ÍC IO S PR O PO STO S
5|  }
6|  println(total)
7| }

(  ) -a) O código se repetirá para sempre, pois a variável x sempre


terá o valor igual a 1.
(  ) -b) Aconteceu um erro de compilação pois na linha 2 pois vari-
ável total foi definida como sendo imutável e na linha 4 esta
variável está sendo modificada.
(  ) -c) O resultado do código acima mostrará os números de 1 até
5 na tela.
(  ) -d) No código acima, temos o uso da expressão for, que vai ite-
rar sobre o intervalo de números inteiros de 1 até 5. E cada
iteração a variável x assumirá cada um dos valores de 1 até
5, estes valores serão acumulados na variável chamada total
que ao final da repetição possuirá a soma dos inteiros de 1
até 5 que é 15, este valor será então mostrado na tela pela
chamada da função println na linha 6.
(  ) -e) No código acima, temos o uso da expressão for, que vai ite-
rar sobre o intervalo de números inteiros de 0 até 4. E cada
iteração a variável x assumirá cada um dos valores de 0 até
4, estes valores serão acumulados na variável chamada total
que ao final da repetição possuirá a soma dos inteiros de 0
até 4 que é 10, este valor será então mostrado na tela pela
chamada da função println na linha 6.

8) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   for (x in 1..10) {
3|    if (x % 2 == 0) {
4|     println(“$x número é tipo1”)
5|    } else {
6|     println(“$x número é tipo2”)

4-16
7|   }
8|  }

EX ER C ÍC IO S PR O PO STO S
9| }

(  ) -a) Na linha 3 o código acima calcula 2 por cento de todos os nú-


meros entre 1 e 10 e se algum valor retornar menor que zero
então a mensagem da linha 4 será mostrada, caso contrário
a mensagem da linha 6 será mostrada.
(  ) -b) Para completar corretamente o código, devemos substituir a
palavra tipo1 na mensagem da linha 4 pela palavra par, e a
palavra tipo2 na linha 6 pela palavra ímpar.
(  ) -c) Para completar corretamente o código, devemos substituir a
palavra tipo1 na mensagem da linha 4 pela palavra ímpar, e
a palavra tipo2 na linha 6 pela palavra par.
(  ) -d) Para completar corretamente o código, devemos substituir a
palavra tipo1 na mensagem da linha 4 pela palavra número
primo e remover as linhas 5, 6 e 7.
(  ) -e) N.d.a.

9) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   for (x in 1..20) {
3|    var y = 2
4|    var tipoNumero = x != 1
5|    while (y <= x && tipoNumero) {
6|     if ((x != y) && (x % y == 0)) {
7|     tipoNumero = false
8|    }
9|     y = y + 1
10|   }
11|    println(“$x tipoNumero $tipoNumero”)
12|  }
13| }

4-17
(  ) -a) O código acima, mostra todos os números pares entre 1 e 20.
(  ) -b) O código acima mostra todos os números primos entre 1 e

EX ER C ÍC IO S PR O PO STO S
20.
(  ) -c) O código acima mostra todos os números não primos entre
1 e 20.
(  ) -d) O código acima mostra a soma de todos os números primos
de 1 até 20.
(  ) -e) N.d.a.

10) Considere o código abaixo, e escolha a alternativa correta:

1| fun main() {
2|   var resultado = 1
3|   for (x in 1..10) {
4|    if (x % 2 != 0) {
5|     resultado = resultado * x
6|   }
7|  }
8|  println(resultado)
9| }

(  ) -a) O código acima multiplica todos os números ímpares entre 1


e 10, e mostra como resultado na tela o valor 945.
(  ) -b) O código acima multiplica todos os números pares entre 1 e
10, e mostra como resultado na tela o valor 3840.
(  ) -c) O código acima soma todos os números pares entre 1 e 10, e
mostra como resultado na tela o valor 30.
(  ) -d) O código acima soma todos os números ímpares entre 1 e 10,
e mostra como resultado na tela o valor 25.
(  ) -e) O código acima soma todos os números primos entre 1 e 10,
e mostra como resultado na tela o valor 17.

4-18
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 3:
APROFUNDANDO NA
LINGUAGEM KOTLIN

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Nesta unidade veremos como organizar o código evitando a


repetição com funções, aprenderemos também a uma das mais
usadas estruturas de dados que são as listas.

Veremos também uma breve introdução à programação


orientada a objetos por meio das definições de classe e herança.

Ótimos estudos!

Conteúdos da Unidade:
Dados organizados em lista, listas mutáveis e imutáveis, de-
finição de funções, funções Single-Expression, funções com pa-
râmetros opcionais, Definindo uma classe, Definindo método e
atributos de uma classe, Sobrecarga de métodos, Herança.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 5:
LISTAS E FUNÇÕES
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
5.1 Introdução
Veremos inicialmente neste capítulo como utilizar listas para
armazenar uma sequência de valores, este conceito será muito útil
mais a frente quando iniciarmos o desenvolvimento do aplicativo.
Na sequência veremos como organizar o código em funções.

5.2 Listas
É muito comum no desenvolvimento de um aplicativo termos
que representar uma lista de elementos, suponha uma lista de com-
pras, onde cada elemento da lista fosse um texto com o nome do
item, não seria nada eficiente, se tivéssemos que criar uma variável
para cada um dos itens desta lista, e imagine só, no caso de uma lista
de compras, poderíamos nem saber o número total de itens.
Considere o código abaixo, onde vamos definir uma lista,
onde cada elemento foi incluído na definição da lista.

1| fun main() {
2|  
val listaCompra =
listOf(“Tomate”,”Batata”,”Açucar”)
3|  println(listaCompra[0])
4| }

Na linha 2 definimos a variável listaCompra, veja que uti-


lizamos a função listOf, onde cada parâmetro é o nome de um
item da lista, na linha 3 acessamos o primeiro item desta lista, note
que os índices começam em 0, neste caso a saída deste programa
será a palavra Tomate.

5-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
Note que para acessar um determinado item de uma posi-
ção usamos o nome da variável seguido do índice entre colchetes
como no caso do código onde acessamos o item 0 escrevendo o
código listaCompra[0].
Caso fosse necessário acessar o valor na segunda posição, usamos
o código listaCompra[2] e com isso acessaremos a palavra Açúcar.
É importante deixarmos claro que a variável listaCompra
não poderá ter seus itens modificados, ou mais itens adicionados ou
até itens removidos, para criarmos uma lista que pode ser modifica-
da, vamos utilizar a função mutableListOf, veja no código abaixo
que agora podemos alterar um item já existente, remover um item
numa determinada posição ou adicionar um item em outra posição.
O código abaixo onde criaremos a variável listaCompra
utilizando a função mutableListOf.

1| fun main() {
val listaCompra = mutableListOf(“Toma-
2|  
te”,”Batata”,”Açucar”)
3|   listaCompra[0] = “Laranja”
4|  listaCompra.add(“Abacate”)
5|  listaCompra.removeAt(2)
6|   for (item in listaCompra) {
7|   println(item)
8|  }
9| }

5-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
Já na linha 2 criamos a variável listaCompra, mas note
que agora utilizamos a função mutableListOf, pois desta vez,
poderemos fazer modificações nesta variável.
Modificamos o item da posição 0 para o texto “Laranja”, em
seguida adicionamos mais um item, identificado pelo texto “Aba-
cate”, note que na linha 4 utilizamos a função add, da lista e pas-
samos como parâmetro o texto “Abacate”, desta maneira este item
será adicionado ao final da lista.
Agora, na linha 5, utilizamos a função removeAt, para re-
mover o item da posição 2, ou seja, removemos a palavra “Açúcar”
da lista. Por fim utilizamos a estrutura de repetição com a instru-
ção for, para percorrer e mostrar todos os elementos da lista na
tela. A saída deste programa será:

Laranja
Batata
Abacate

5.3 Funções
Imagine que precisamos mostrar no programa uma mensa-
gem de erro em vários pontos do código, poderíamos escrever essa
mesma mensagem em vários lugares, mas imagine se por acaso,
tivéssemos que mudar a mensagem, então teríamos que modificar
todos esses pontos do código.
Por meio das funções podemos escrever este código uma
única vez, dentro de uma função e chamar essa função em vários
pontos do nosso código. Caso fosse necessário mudarmos esta

5-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
mensagem, teríamos apenas que modificar o código de dentro
da função.
Outra utilidade muito importante das funções é que por meio
delas melhoramos a organização do código, isolando partes do código
responsáveis por uma tarefa dentro de uma mesma função. Logo abai-
xo, escrevemos de maneira genérica como é a estrutura de uma função:

1| fun nomeDaFuncao(param1:Tipo1, ... pa-


ramN:TipoM) : Tipo {
2|
3|  
Código que será executado quando a
função for chamada
4|
5|   return valor
6| }

O primeiro código que precisamos escrever quando vamos


definir uma função é a palavra-chave fun, isso indica ao compila-
dor que uma função começará a ser escrita.
Na sequência devemos escrever o nome da função, é conside-
rado uma boa prática na programação, escrevemos o nome de uma
função começando por um verbo e na sequência uma palavra que
define o objetivo da função.
Logo após o nome da função abrimos um parêntese e escre-
vemos os parâmetros que a função recebe. Podemos ter um núme-
ro finito de parâmetros ou podemos ter funções que não precisam
de parâmetros, se esse for o caso basta fechar o parêntese sem es-
crever nenhum parâmetro.

5-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
Cada parâmetro de uma função deverá ter o seu tipo decla-
rado, isso é feito pelo uso do símbolo dois-pontos, colocado logo
após o nome do parâmetro. Após o símbolo dois-pontos devemos
escrever o tipo do parâmetro.
Por fim, fechamos o parêntese e usamos novamente o símbo-
lo dois-pontos, só que agora iremos definir qual o tipo do retorno
da função, portanto logo depois deste símbolo devemos escrever
o tipo de retorno, lembre-se que uma função não precisa retornar
nenhum valor, ou seja esta parte pode ser omitida.
Nesta mesma linha terminamos a declaração da função uti-
lizando o símbolo abre chave {. Até agora o que escrevemos pode
ser considerado a assinatura da função. O código que a função exe-
cuta virá na próxima linha, este será o código que vai ser executado
quando a função for chamada.
Por fim, caso a função retorne um valor, devemos escrever a
palavra chave return, colocando um espaço em branco e escre-
vendo um valor literal ou o nome de uma variável, que sejam do
mesmo tipo do retorno declarado na assinatura da função.
Terminamos então a definição de função, usando o símbolo
da chave }.
Logo abaixo, escrevemos uma função, que apenas irá mos-
trar uma mensagem genérica simulando que um erro aconteceu.

1| fun mostraMensagemDeErro() {
2|  
println(“Um erro aconteceu tente
mais tarde !”)
3| }
4|

5-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
5| fun main() {
6|  mostraMensagemDeErro()
7| }

Inicialmente, na linha 1, definimos a função mostraMensa-


gemDeErro, veja que para isso utilizamos a palavra-chave fun,
seguida do nome da função. Perceba que esta função não receberá
nenhum parâmetro, pois apenas queremos mostrar uma mensa-
gem, portanto logo depois do nome da função apenas abrimos e
fechamos os parênteses.
Observe também que não definimos o tipo de retorno desta
função, pois não iremos retornar nada, apenas mostraremos uma
mensagem, podemos então finalizar a assinatura desta função es-
crevendo o símbolo abre chave {.
Na linha 2 escrevemos o código que será executado sem-
pre que a função for chamada, neste caso, estamos utilizando o
println, para mostrar na tela a mensagem descrita.
Por fim terminamos a definição da função, fazendo uso do
símbolo fecha chaves }.
Desde o começo dos exemplos escritos neste material, utili-
zamos a função main, esta é uma função especial, pois ela é cha-
mada sempre que executamos o programa, portanto ela é o inicial
da execução do programa, é dentro da função main que iremos
chamar a função mostraMensagemErro, da maneira como foi
escrito na linha 6, veja que utilizamos o nome da função e os sím-
bolos abre parêntese e fecha parêntese para indicarmos que quere-
mos executar o código desta função.
Agora vamos escrever uma função que calcula a área de um
retângulo, veja que para isso precisaremos de 2 parâmetros, como

5-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
vamos considerar que os valores da base e do lado do retângulo
podem ter casas decimais, vamos utilizar o tipo Double para estes
dois parâmetros.
Esta função também terá um valor de retorno que será a área
do retângulo, este valor também será do tipo Double. Veja abaixo
como ficou o código desta função:

1| fun calculaAreaRetangulo(base:Double,
altura:Double):Double {
2|   return base * altura
3| }
4|
5| fun main() {
6|  val area = calculaAreaRetangulo(5.5, 3.7)
7|   println(“A área do retângulo é $area”)
8| }

Novamente começamos com a palavra-chave fun, que defi-


ne o começo da declaração de uma função, em seguida colocamos
um espaço em branco e escrevemos o nome da função, que neste
caso será calculaAreaRetangulo.
Seguindo as boas práticas iniciamos o nome da função com
um verbo, seguido de uma breve explicação sobre o que a função faz.
Neste caso, como a função vai calcular a área de um retân-
gulo, precisamos receber dois parâmetros, o primeiro será a base
e o segundo será a altura, como queremos usar casas decimais no
cálculo, utilizaremos o tipo Double, para ambos.

5-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
Note que colocamos os parâmetros entre parênteses, na se-
quência utilizamos o símbolo dois pontos, para indicarmos que a
função irá retornar um valor do tipo Double.
Vamos então começar o código da função, para indicar isso,
devemos usar o símbolo abre chaves {. Na linha 2 escrevemos o
código que será usado para calcular a área do retângulo, ou seja
multiplicamos os parâmetros base e altura, e nesta mesma li-
nha retornamos o valor da multiplicação.
Por fim, terminamos a definição completa da função com o
símbolo fecha chaves }. Como dito anteriormente, ao executarmos
o programa, o compilador procura a função main como ponto de
execução inicial, neste caso definimos a função main na linha 5,
e logo na linha 6 chamamos a função calculaAreaRetangu-
lo, passando como parâmetros os valores 5.5 para base e 3.7 para
altura, note que armazenamos o resultado da função na variável
imutável chamada área, e por fim mostramos este valor na saída
do programa.
A linguagem Kotlin fornece um recurso para simplificarmos
a declaração de funções como essa que podem ser escritas com
apenas uma linha, chamamos este recurso de Single-Expres-
sion functions, vamos reescrever a função calculaAreaRe-
tangulo, utilizando este recurso:

1| fun calculaAreaRetangulo(b:Double, a:-


Double) = b * a

Veja que a linguagem Kotlin é capaz de identificar que o re-


torno da função será do tipo Double, e que o valor retornado de-
verá vir depois do símbolo igual e será dado pela multiplicação dos
parâmetros b e a.

5-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
O nome dos parâmetros foi modificado apenas para a decla-
ração da função caber em uma linha no formato deste material.
Podemos também definir uma função com parâmetros op-
cionais veja no código abaixo como essa função pode ser escrita:

1| fun calculaAreaQuadrado(lado: Double,


unidade: String = “mm²”) {
2|   val area = lado * lado
println(“A área do quadrado é $area $unidade”)
3|  
4| }

Quando queremos definir uma função com um parâmetro


opcional, devemos fazer como na linha 2 onde definimos o parâ-
metro unidade, que é do tipo String, porém note que utilizamos o
operador de atribuição e demos a este parâmetro um valor padrão,
isso faz com que quando este parâmetro possa omitido na chama-
da da função.
Neste caso quando omitimos o parâmetro unidade a função
utilizará o valor mm², como valor do parâmetro e na linha 4 será
mostrada uma mensagem na tela com esse valor, veja no código
abaixo, como utilizar este recurso na chamada da função:

1| fun main() {
2|  calculaAreaQuadrado(3.0)
3|  calculaAreaQuadrado(2.0,”cm²”)
4| }

5-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 5

LIS TAS E FU N ÇÕ ES
Perceba que na linha 2, fizemos uma chamada para a função
calculaAreaQuadrado, passando como parâmetro apenas o va-
lor do lado do quadrado omitindo o parâmetro do tipo String que
representa a unidade de área.
Na sequência, fizemos uma chamada para a função calcu-
laAreaQuadrado, porém, agora passamos o segundo parâmetro
que representa a unidade da área do quadrado como sendo cm²,
neste caso, esta String fará parte da mensagem gerada pela fun-
ção e substituirá a String padrão.
Veja abaixo que a saída do programa mostra na linha 1 que a
área do quadrado é 9 mm², pois na primeira chamada omitimos o
parâmetro e neste caso o valor padrão foi usado. Na linha 2, porém
a mensagem mostrada na tela, aparece com a unidade cm²

1| A área do quadrado é 9.0 mm²


2| A área do quadrado é 4.0 cm²

5-12
 EXERCÍCIOS PROPOSTOS

1) Considere o código abaixo e escolha a afirmativa correta:

1| fun main() {
2|  val listaDeItens = listOf(“Barraca”,
3|  “Fogareiro”,
4|  “Faca”,
5|  “Garfo”)
6|  println(listaDeItens.count())
7|  println(listaDeItens[0])
8|  println(listaDeItens[3])
9| }

(  ) -a) O código vai dar um erro durante a execução, pois o índice 0,


acessado na linha 6, não existe.
(  ) -b) Existe um erro no código pois não podemos criar uma lista
sem definir o tipo da variável.
(  ) -c) O programa acima executa com sucesso, e como saída mos-
trará na tela o valor 4, pois a lista tem 4 elementos, mostrará
também o texto Barraca, pois é esse o valor que está arma-
zenado no índice 0 e por fim o texto Garfo que é o valor que
está armazenado no índice 3.
(  ) -d) O programa acima executa com sucesso, e como saída mos-
trará na tela o valor 4, pois a lista tem 4 elementos, mostrará
também o texto Barraca, pois é esse o valor que está armaze-
nado no índice 0 e por fim o texto Faca que é o valor que está
armazenado no índice 3.
(  ) -e) N.d.a

5-13
2) Considere o código abaixo e escolha a afirmativa correta:

EX ER C ÍC IO S PR O PO STO S
1| fun main() {
2|   val listaDeItens = listOf(“Barraca”,
3|  “Fogareiro”,
4|  “Faca”,
5|  “Garfo”)
6|
7|   listaDeItens[0] = “Lanterna”
8|  listaDeItens.add(“Cobertor”)
9| }

(  ) -a) O Código acima não vai funcionar, pois a lista criada pela
instrução listOf não pode ser modificada.
(  ) -b) O Código vai falhar pois a indexação da lista começa sempre
no índice 1 e nunca no 0.
(  ) -c) Como a lista foi criada com listOf a linha 7 vai executar com
sucesso, porém a linha 8 vai falhar pois não podemos adicio-
nar um novo elemento.
(  ) -d) Como a lista foi criada com listOf a linha 7 vai falhar, porém,
a linha 8 vai executar com sucesso pois podemos adicionar
um novo elemento.
(  ) -e) Basta mudar a palavra chave de val para var e o resto do có-
digo vai ser executado com sucesso.

3) Considere o código abaixo e escolha a afirmativa correta:

10| fun main() {


11|   val listaDeItens = mutableListOf(“Barraca”,
12|  “Fogareiro”,
13|  “Faca”,
14|  “Garfo”)
15|   listaDeItens[0] = “Lanterna”
16|  listaDeItens.add(“Cobertor”)

5-14
17|  listaDeItens.removeAt(1)
18|  println(listaDeItens.count())

EX ER C ÍC IO S PR O PO STO S
19|   for (item in listaDeItens) {
20|   println(item)
21|  }
22| }

(  ) -a) O código acima não vai compilar pois na linha 2 foi utiliza-
da a palavra chave val, o que tornará a variável listaDeItens
imutável, e portanto ela não poderá ser alterada nas linhas
abaixo.
(  ) -b) Teremos um erro na compilação gerado pela linha 6 pois o
índice 0 não existe na lista, sempre devemos começar pelo
índice 1.
(  ) -c) O código executa e a resposta será:
4
Lanterna
Faca
Garfo
Cobertor
(  ) -d) O código executa e a resposta será
3
Barraca
Faca
Cobertor
(  ) -e) Existe um erro na linha 10, pois não foi utilizado um índice
na declaração do laço de repetição for.

4) Considere o código abaixo e escolha a afirmativa correta:

1| fun main() {
2|   val notas = listOf(5.3,
3|  7.1,
4|  8.2,
5|  6.6)

5-15
6|
7|   var variavel1 = 0.0

EX ER C ÍC IO S PR O PO STO S
8|   for (nota in notas) {
9|    variavel1 = variavel1 + nota
10|  }
11|   val variavel2 = variavel1 / notas.count()
12|  println(variavel2)
13| }

(  ) -a) O objetivo do programa acima é calcular a média aritmética


dos valores da lista armazenada na variável notas.
(  ) -b) O programa acima, vai calcular a soma de todos os valores
da lista, porém na linha 11 teremos um erro pois o valor de
notas.count() será igual a zero.
(  ) -c) O objetivo deste programa é calcular a média aritmética dos
valores armazenados na lista de notas, porém estes valores
estão armazenados na variável chamada variavel1, ou seja, o
programa vai mostrar o valor errado quando executar.
(  ) -d) O programa vai executar com erro, pois a lista de notas foi
declarada como sendo imutável.

5) Considerando o conceito de função, escolha a alternativa que possui a


afirmação correta:

(  ) -a) Uma função na linguagem Kotlin sempre deve ter o seu tipo
de retorno declarado, mesmo quando essa função não retor-
nar nenhum valor.
(  ) -b) É obrigatório na linguagem Kotlin, que uma função receba
pelo menos um parâmetro.
(  ) -c) Na linguagem Kotlin, podemos declarar uma função apenas
utilizando a palavra-chave fun, sem passar nenhum parâme-
tro e sem definir o seu tipo de retorno.
(  ) -d) Na linguagem Kotlin, não é necessário o uso de chaves para
marcar o bloco de código de uma função de mais de uma
linha.
(  ) -e) N.d.a.

5-16
6) Considere o código abaixo e escolha a afirmativa correta:

EX ER C ÍC IO S PR O PO STO S
1| fun calculaAreaCirculo(r:Double) = PI
* r.pow(2)

(  ) -a) A função declarada acima está errada pois faltam os símbo-


los abre e fecha chaves.
(  ) -b) A função declarada acima está correta.
(  ) -c) Existe um erro na função declarada acima, pois o seu tipo de
retorno não foi declarado.
(  ) -d) O Valor PI não existe, por isso teremos um erro de execução.
(  ) -e) Não podemos chamar o atributo pow do parâmetro r.

7) Considere o código abaixo e escolha a afirmativa correta:

fun calculaArea(l1: Double, l2: Double = l1) = l1 * l2

(  ) -a) A função acima multiplica o valor do parâmetro l1 pelo valor


do parâmetro l2 e quando o parâmetro l2 é omitido a função
vai elevar ao quadrado o valor do parâmetro l1, pois nesta
função o parâmetro l2 foi declarado como opcional.
(  ) -b) A função declarada acima está errada pois faltam os símbo-
los abre e fecha chaves.
(  ) -c) Existe um erro na função declarada acima, pois o seu tipo de
retorno não foi declarado.
(  ) -d) O parâmetro l2 foi declarado como opcional de maneira in-
correta pois devemos declarar um parâmetro opcional ape-
nas igualando ele a um valor literal.
(  ) -e) Podemos omitir o tipo de cada um dos parâmetros.

8) Sobre a palavra-chave return responda:

(  ) -a) A palavra-chave return sempre marca o final de uma função.


(  ) -b) Devemos usar a palavra-chave return mesmo quando a fun-
ção não possui um tipo de retorno definido.

5-17
(  ) -c) Podemos usar a palavra-chave return para retornar um va-
lor ao final da função mesmo que essa função não possua um

EX ER C ÍC IO S PR O PO STO S
tipo definido.
(  ) -d) A palavra-chave return pode vir por fora das chaves que de-
finem o bloco de código da função.
(  ) -e) N.d.a.

9) O código abaixo possui alguns erros, escolha a alternativa correta que


conserta todos os erros:

1| fun retornaNumeros(listaDeNumeros: Lis-


t<Int>): List<Int> {
2|   val resultado = listOf<Int>()
3|   for (numero in listaDeNumeros) {
4|    if numero % 2 = 0 {
5|    resultado.add(numero)
6|   }
7|  }
8|   return resultado
9| }

(  ) -a) Para consertarmos o código acima, apenas precisamos colo-


car a expressão condicional da linha 4 entre parênteses.
(  ) -b) Precisamos colocar a expressão condicional da linha 4 entre
parênteses, adicionar mais um sinal de igual, essa expressão,
pois ela está fazendo uma atribuição e por fim devemos usar
na linha 2 a instrução mutableListOf
(  ) -c) Basta usarmos a instrução mutableListOf no lugar da ex-
pressão listOf.
(  ) -d) Basta colocarmos a expressão condicional da linha 4 entre
parênteses.
(  ) -e) Precisamos apenas modificar o operador relacional que pos-
sui apenas um sinal de igual para operador que possui dois
sinais iguais.

5-18
10) Considere o código abaixo e escolha a afirmativa correta:

EX ER C ÍC IO S PR O PO STO S
1| fun retornaNumeros(listaDeNumeros: Lis-
t<Int>): List<Int> {
2|   val resultado = mutableListOf<Int>()
3|   for (numero in listaDeNumeros) {
4|    if (numero % 2 == 0) {
5|    resultado.add(numero)
6|   }
7|  }
8|   return resultado
9| }

(  ) -a) O código descrito acima, retorna uma lista com apenas os


números ímpares do parâmetro listaDeNumeros.
(  ) -b) O código acima retorna uma lista com apenas os números
primos da lista que foi passada como parâmetro.
(  ) -c) O código descrito acima, retorna uma lista com apenas os
números pares do parâmetro listaDeNumeros.
(  ) -d) O código acima não compila, pois não podemos usar o mé-
todo add da lista.
(  ) -e) N.d.a.

5-19
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 6:
CLASSES
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
6.1 Introdução
Veremos neste capítulo uma breve introdução ao conceito
de classe que é fundamental da programação orientada a obje-
tos e que será necessário para o desenvolvimento dos aplicativos
deste material.
A programação orientada a objetos modela os elementos uti-
lizados no mundo real em classes, as classes funcionam como mol-
des que serão utilizados na construção de objetos.
O conceito de classe é muito importante quando vamos de-
senvolver aplicativos para a plataforma Android, pois para utilizar-
mos corretamente a biblioteca de maneira confortável precisamos
saber o básico sobre este conceito.

6.2 Definindo uma Classe


Vamos usar um exemplo do mundo real e vamos construir
uma classe que modela um quadrilátero, da geometria elementar,
temos que um quadrilátero é um polígono que possui quatro lados,
logo nossa classe deverá ter propriedades que vão armazenar os
valores destes quatro lados, veja abaixo como vai ficar a definição
desta classe:

1| class Quadrilatero(l1: Double,


2| l2: Double,
3| l3: Double,
4| l4: Double) {
5|

6-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
6|   var nome = “Quadrilatero”
7|   val l1 = l1
8|   val l2 = l2
9|   val l3 = l3
10|   val l4 = l4
11| }

Começamos definindo a classe utilizando a palavra-chave


class, deixamos um espaço em branco e escrevemos o nome da
classe, que neste caso chamamos do Quadrilatero, é uma boa
prática no desenvolvimento de software colocarmos a primeira
letra do nome de uma classe em maiúsculo.
Da geometria, sabemos que não existe um quadrilátero que
não possua exatamente quatro lados, por isso definimos as pro-
priedades l1, l2, l3 e l4 para armazenarmos os valores de cada
um dos lados.
Como precisamos dos valores dos 4 lados, incluímos eles
como parâmetros do construtor da classe. Em Kotlin, declaramos
os parâmetros do construtor da classe entre parênteses logo depois
do nome.
Ao final da declaração do construtor utilizamos o símbolo
abre chave {, para marcar onde começa o código da classe. Na li-
nha 6 definimos um atributo chamado nome, que armazenará o
nome do nosso quadrilátero.
Nas linhas de 7 até 10, criamos as variáveis l1, l2, l3 e l4
que serão inicializadas com os valores passados para o construtor
por fim na linha 11 terminamos a declaração da classe Quadrila-
tero, usando o símbolo fecha chave }.

6-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
Agora que temos a classe Quadrilatero definida, vamos
ver como podemos instanciar um objeto dessa classe e utilizar os
seus atributos.

1| fun main() {
2|  
val quadrilatero =
Quadrilatero(3.0,7.0,5.0,8.0)
3|   quadrilatero.nome = “Meu Quadrilatero”
4|  
println(“O nome do quadrilatero é:
${quadrilatero.nome}”)
5|  
println(“O valor de um dos lados é:
${quadrilatero.l1}”)
6| }

Novamente utilizamos a função main que é o ponto de entra-


da de execução do programa, e na linha 2 criamos uma instância
da classe Quadrilatero, quando criamos uma instância de uma
classe, o compilador do Kotlin reserva um espaço para o objeto
na memória e atribui a variável imutável quadrilatero o endereço
deste objeto.
Feito isso podemos acessar os atributos deste novo objeto
por meio do operador ponto. Isso acontece na linha 3 onde atri-
buímos um nome para a propriedade nome da instância apontada
pela variável imutável chamada quadrilatero. Na linha 4 mos-
tramos que esse valor está realmente armazenado na proprieda-
de nome da classe e na sequência, na linha 5 mostramos o valor
do atributo l1.

6-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
6.3 Definindo métodos em uma Classe
Além de atributos, uma classe também pode conter funções,
que por estarem em uma classe chamaremos de método por con-
venção. Vamos tomar como exemplo, o caso de queremos escre-
ver um método que calcula o perímetro do quadrilátero, da mate-
mática elementar sabemos que o perímetro é dado pela soma dos
comprimentos dos lados do quadrilátero. Veja no código abaixo a
implementação deste método:

1| class Quadrilatero(l1: Double,


2| l2: Double,
3| l3: Double,
4| l4: Double) {
5|   var nome = “Quadrilatero”
6|
7|   val l1 = l1
8|   val l2 = l2
9|   val l3 = l3
10|   val l4 = l4
11|
12|   fun calculaPerimetro(): Double {
13|    return l1 + l2 + l3 + l4
14|  }
15| }

6-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
A definição da classe é a mesma que fizemos anteriormente,
porém agora na linha 12 definimos o método calculaPerime-
tro, veja que este método não recebe nenhum parâmetro, e retor-
na como valor um valor do tipo Double, que será a soma de todos
os lados, ou seja será dado pela soma dos atributos l1, l2, l3 e
l4. Veja que utilizamos a palavra return para retornar o valor
desta soma.
Pronto a classe Quadrilatero, agora possui um método
que calcula o perímetro, mas como vamos utilizar este novo méto-
do? Para isso devemos fazer como no código abaixo:

1| fun main() {
2|  
val quadrilatero =
Quadrilatero(3.0,7.0,5.0,8.0)
3|  
val perimetro = quadrila-
tero.calculaPerimetro()
4|  println(perimetro)
5| }

Inicialmente, precisamos de uma instância da classe Qua-


drilatero, para isso, na linha 2 definimos o objeto quadrila-
tero, utilizando o operador de atribuição, representado pelo sinal
igual, e chamamos o construtor da classe passando como valor o
comprimento de cada lado do quadrilátero.
Agora que temos uma instância da classe Quadrilatero,
vamos fazer uso do método calculaPerimetro, portanto o valor
retornado por esse método será armazenado na variável imutável
chamada perimetro, por fim na linha 4 apenas mostramos o va-
lor desta variável.

6-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
No capítulo anterior, mostramos que as funções podem ter
parâmetros opcionais, declaramos isto quando, na definição do pa-
râmetro atribuímos a ele um valor.
Podemos utilizar este mesmo recurso, quando definimos os
parâmetros necessários ao construtor de uma classe. Definimos o
construtor da classe Quadrilatero com 4 parâmetros obrigató-
rios, mas pense no caso onde queremos construir uma instância
da classe Quadrilatero, que irá representar um retângulo, neste
caso, como o retângulo possui dois pares de lados iguais, seriam
necessário apenas dois parâmetros.
Vamos então, no código abaixo, reescrever o construtor da
classe Quadrilatero, seguindo essas ideias.

1| class Quadrilatero(l1: Double,


2| l2: Double,
3| l3: Double = l1,
4| l4: Double = l2) {
5|   var nome = “Quadrilatero”
6|
7|   val l1 = l1
8|   val l2 = l2
9|   val l3 = l3
10|   val l4 = l4
11|
12|   fun calculaPerimetro(): Double {
13|    return l1 + l2 + l3 + l4

6-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
14|  }
15| }

Aqui a diferença está nas linhas 3 e 4, veja que escrevemos


que o valor padrão para o parâmetro l3 é o parâmetro l1, ou seja
quando o parâmetro l3 for omitido, seu valor padrão será igual
ao parâmetro l1.
Do mesmo jeito, escrevemos que o valor padrão do parâme-
tro l4, será o valor do parâmetro l2. Vamos testar como ficou este
conceito, para isso utilizamos o código abaixo:

1| fun main() {
2|  val quadrilatero = Quadrilatero(10.0, 3.0)
3|  
val perimetro = quadrila-
tero.calculaPerimetro()
4|
5|   println(“Lado1 ${quadrilatero.l1}”)
6|   println(“Lado2 ${quadrilatero.l2}”)
7|   println(“Lado3 ${quadrilatero.l3}”)
8|   println(“Lado4 ${quadrilatero.l4}”)
9|
10|   println(“Perimetro $perimetro”)
11| }

Na linha 2 construímos o objeto chamado quadrilatero,


perceba que desta vez utilizamos o construtor da classe Quadri-
latero com apenas dois parâmetros, de valores 10.0 e 3.0, nas

6-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
linhas de 5 até 8 mostramos os valores de cada um dos lados, note
que para os lados l3 e l4 deveremos ter respectivamente os valo-
res 10.0 e 3.0, veremos que isso acontece na saída deste programa,
por fim apenas mostramos na tela o valor do cálculo do perímetro
para provarmos que, com a alteração do construtor o perímetro
continua sendo calculado corretamente. Veja abaixo como ficou a
saída do programa:

Lado1 10.0
Lado2 3.0
Lado3 10.0
Lado4 3.0
Perimetro 26.0

6.4 Sobrecarga de métodos


No exemplo anterior precisamos escrever, nas linhas de 5 até
8 as chamadas para a função println, imagine se fosse possível
escrever este código todo dentro da própria classe, de maneira que
sempre que fosse necessário, mostrarmos esta informação na tela,
apenas chamamos este método.
Como a linguagem Kotlin utiliza muitos conceitos da lin-
guagem Java, podemos utilizar o método toString, que existe
em todos objetos, para realizar esta tarefa, o método toString, é
chamado quando passamos o objeto como parâmetro para a fun-
ção println.
Este método retorna um texto do tipo String que será
mostrado na tela pela função println, para isso utilizaremos a

6-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
palavra override, que diz ao compilador que iremos sobrescre-
ver este método com uma nova implementação.
Veja abaixo como vai ficar o código da classe Quadrilate-
ro com o método toString sobrescrito:

1| class Quadrilatero(l1: Double,


2| l2: Double,
3| l3: Double = l1,
4| l4: Double = l2) {
5|   var nome = “Quadrilatero”
6|
7|   val l1 = l1
8|   val l2 = l2
9|   val l3 = l3
10|   val l4 = l4
11|
12|   fun calculaPerimetro(): Double {
13|    return l1 + l2 + l3 + l4
14|  }
15|
16|   override fun toString(): String {
17|   return “””
18|    O Poligono chamado $nome
19|    possui 4 lados com comprimentos

6-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
20|    $l1, $l2, $l3, $l4 .”””
21|  }
22| }

A modificação feita começa na linha 16, note que utiliza-


mos a palavra-chave override, que informa ao compilador
que iremos sobrescrever o método toString, com a nossa pró-
pria implementação.
Para que a sobrescrita do método seja feita corretamente
precisamos escrever exatamente a mesma assinatura do método
existente, ou seja, o nome do método, os parâmetros recebidos e o
tipo de retorno deverá ser o mesmo do método original.
Por isso na linha 16 escrevemos, logo após a palavra-chave
override, o nome do método que é toString, seguido dos sím-
bolos abre e fecha parênteses, pois o método não recebe nenhum
parâmetro, e na sequência utilizamos o símbolo dois pontos e in-
formamos o tipo de retorno que deverá ser String.
Feito isso utilizamos o símbolo abre chaves {, e escrevemos
o código que vai ser executado quando este método for chamado.
Neste caso apenas iremos mostrar uma mensagem com o
nome do quadrilátero, ou seja, o valor que está armazenado no
atributo nome e o valor de cada um dos 4 lados, que estão armaze-
nados nos atributos l1, l2, l3 e l4.
Para isso, na linha 17 utilizamos a palavra-chave return,
note que ao invés de utilizarmos um símbolo de aspas duplas, uti-
lizamos três deles, isso diz ao compilador que podemos escrever a
String com várias linhas, preservando até a formatação.

6-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
Se não utilizássemos a sequência de três aspas duplas, te-
ríamos que concatenar todos os valores, o que deixaria o código
difícil de ler.
Por fim fechamos, utilizamos o símbolo fecha chaves } e fi-
nalizamos o método. Pronto, agora toda a vez que for necessário
mostrar informações sobre a classe Quadrilatero, basta apenas
instânciarmos o objeto e passar a sua referência para a função
println, isso foi feito no código abaixo:

1| fun main() {
2|  val quadrilatero = Quadrilatero(10.0, 3.0)
3|   quadrilatero.nome = “Retângulo”
4|  println(quadrilatero)
5| }

Na linha 2 criamos uma nova instância da classe Quadri-


latero, note que omitimos 2 parâmetros pois estamos criando a
representação de um retângulo.
Modificamos o nome do quadrilatero na linha 3 para Re-
tângulo, e por fim na linha 4, utilizamos a função println e pas-
samos como referência o objeto quadrilatero criado na linha 2,
a saída deste programa será:

O Poligono chamado Retângulo


possui 4 lados com comprimentos
10.0, 3.0, 10.0, 3.0 .

6-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
Veja que o texto da saída é exatamente o texto que foi es-
crito no corpo do método toString que foi sobrecarregado na
classe Quadrilátero.

6.5 Herança de classes


Um conceito muito importante da programação orientada a
objetos é o conceito de herança. Para explicar este conceito, consi-
dere a nossa classe Quadrilatero, vamos supor que agora, que-
remos escrever uma nova classe que vai representar um retângulo.
Sabemos da geometria elementar que os retângulos são um
tipo especial de quadrilátero que possui os quatro ângulos internos
com valor de 90 graus e 2 pares de lados iguais. Sabemos também
que podemos calcular a área do retângulo multiplicando sua base
pela altura
Vamos então criar uma nova classe chamada Retangulo,
que vai ter como classe mãe a classe Quadrilatero, deste modo
não precisaremos implementar os atributos l1, l2, l3 e l4 pois
herdaremos estes atributos da classe Quadrilatero.
Pelo mecanismo de herança também herdaremos o método
calculaPerimetro, e o método sobrescrito toString. Antes
de fazermos o código da herança, precisamos marcar a classe Qua-
drilatero com o modificador open, pois por padrão as classes
definidas em Kotlin são marcadas como final, ou seja, não po-
demos usar herança por padrão, sem antes usarmos o modifica-
dor open.

1| open class Quadrilatero(l1: Double,


2| l2: Double,

6-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
3| l3: Double = l1,
4| l4: Double = l2) {
5|  :
6|  :
7| }

Para economizar algumas linhas, colocamos apenas a assi-


natura da classe Quadrilatero, agora marcada com o modifica-
dor open, feito isso poderemos usar o mecanismo de herança para
criarmos a classe Retangulo.
Feito isso, vamos escrever a classe Retangulo, como sendo
filha da classe Quadrilatero, veja no código abaixo, como ficou
esta implementação:

8| class Retangulo(l1: Double,


9| l2: Double,
10| l3: Double = l1,
11| l4: Double = l2):
12| Quadrilatero(l1,l2,l3,l4) {
13|
14|   init {
15|    this.nome = “Retângulo”
16|  }
17|
18|   fun calculaArea(): Double {
19|    return l1 * l2

6-14
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
20|  }
21| }

Já no começo do código, utilizamos novamente a palavra-


-chave class e na sequência colocamos o nome da classe, que
neste caso será Retangulo.
Da mesma maneira como definimos o construtor da classe
Quadrilatero, abrimos um parênteses logo depois do nome da
classe e definimos os 4 parâmetros que representam os lados do
retângulo. Na linha 4 do código utilizamos o símbolo dois pon-
tos e na sequência escrevemos o nome da classe Quadrilatero.
É nesta parte do código que informamos ao compilador que a
classe Retangulo é filha da classe Quadrilatero.
Na linha 7 declaramos o bloco init, fazendo isto definimos
um bloco de inicialização, ou seja, quando um objeto do tipo Re-
tangulo for instanciado, o código deste bloco init será executado.
E neste caso, como estamos instanciando um objeto do tipo
Retângulo, faz sentido mudarmos o texto padrão do atributo nome
para Retângulo.
Como dito anteriormente, vamos criar um método que cal-
cula a área do retângulo, da geometria elementar, sabemos que a
área é dada pela multiplicação do comprimento da base pelo com-
primento da altura, vamos assumir que ambos os valores estarão
armazenados nos atributos l1 e l2. E na linha 11 definimos o mé-
todo calculaArea, este método não precisa de receber nenhum
parâmetro pois para efetuar o cálculo utilizamos os atributos l1 e
l2, o valor da área será então retornado pelo método, por isso defi-
nimos em sua assinatura que o tipo de retorno será Double.

6-15
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 6

CLASSES
Com isso temos a classe Retângulo, pronta para ser utiliza-
da, veja no código abaixo como fazer uso desta nova implementação:

1| fun main() {
2|   val retangulo = Retangulo(3.0, 7.0)
3|   val area = retangulo.calculaArea()
4|   println(“Área do ${retangulo.nome} é $area”)
5|   perimetro = retangulo.calculaPerimetro()
6|  println(“Perimetro do ${retangulo.nome}
é $perimetro”)
7| }

Desta vez começaremos criando uma instância da classe Re-


tangulo, para isso chamamos o construtor da classe passando os
valores dos lados l1 e l2.
Na sequência na linha 3 utilizamos o método calculaArea,
lembre-se que não precisamos passar nenhum parâmetro pois os
valores para o cálculo da área estão armazenados no l1 e l2. Neste
caso a linha 4 irá mostrar em seu texto o valor 21.
Logo abaixo, na linha 5, utilizamos o método calcula-
Perimetro, lembre-se que não implementamos este método na
classe Retângulo, mas sim na classe Quadrilatero, mas por
meio do mecanismo de herança, podemos usar este método sem
problemas, teremos então no texto exibido pela função println
da linha 6 o valor 20.

6-16
 EXERCÍCIOS PROPOSTOS

1) Sobre o conceito de classe escolha a alternativa verdadeira:

(  ) -a) O conceito de classe não faz parte da programação orientada


a objetos.
(  ) -b) Não é uma boa prática começarmos o nome de uma classe
com uma letra maiúscula.
(  ) -c) A linguagem Kotlin exige que a primeira letra do nome de
uma classe seja maiúscula.
(  ) -d) Para usar a biblioteca de código da plataforma Android não
precisamos entender o conceito de classe pois essa bibliote-
ca não é orientada a objetos.
(  ) -e) A programação orientada a objetos, modela elementos uti-
lizados no mundo real em classes e as classes funcionam
como moldes que serão utilizados na construção de objetos.

2) Considere o código abaixo e escolha a alternativa correta:

1| class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|
5|   val nome = nome
6|   var pontosDeVida = pontosDeVida
7|   var pontosDeAtaque = pontosDeAtaque
8| }

(  ) -a) O código acima declara uma classe chamada Herói, com os


atributos nome, pontosDeVida e pontosDeAtaque. O atribu-
to nome não poderá ser modificado posteriormente pois foi
definido pela palavra-chave val.

6-17
(  ) -b) O código acima declara uma classe chamada Heroi, com os
atributos nome, pontosDeVida e pontosDeAtaque. O atribu-

EX ER C ÍC IO S PR O PO STO S
to nome poderá ser modificado posteriormente.
(  ) -c) Podemos construir objetos do tipo Herói, sem passar nenhum
parâmetro para o construtor, pois os parâmetros são opcionais.
(  ) -d) Depois que instanciamos um objeto do tipo Herói, não podere-
mos modificar os atributos pontosDeVida nem pontosDeAtaque.
(  ) -e) N.d.a

3) Considere o código abaixo e escolha a alternativa correta:

1| class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|   val nome = nome
5|   var pontosDeVida = pontosDeVida
6|   var pontosDeAtaque = pontosDeAtaque
7|   fun sofreDano(pontosDeDano: Double): Double {
8|   pontosDeVida = pontosDeVida - pontosDeDano
9|    if (pontosDeVida <= 0) {
10|    println(“O Herói morreu.”)
11|   }
12|   return pontosDeVida
13|  }
14| }
15|
16| fun main() {
17|   var heroi = Heroi(“Conan”, 40.0, 59.0)
18|  println(“Pontos de vida ${he-
roi.pontosDeVida}”)
19|   var pontosRestantes = heroi.sofreDano(10.0)
20|   println(“Herói sofreu dano,
21|  pontos de vida restantes $pontosRestantes”)
22|  heroi.sofreDano(100.0)
23| }

6-18
(  ) -a) O método descrito na linha 7 vai gerar um erro pois o atribu-
to pontosDeVida não pode ser modificado.

EX ER C ÍC IO S PR O PO STO S
(  ) -b) A saída deste programa será: Pontos de vida 40.0, Herói so-
freu dano, pontos de vida restantes 30.0, O Herói morreu.
(  ) -c) A saída deste programa será: Pontos de vida 40.0, Herói so-
freu dano, pontos de vida restantes 30.0.
(  ) -d) O programa irá gerar um erro pois o método sofreDano não
foi marcado como public.
(  ) -e) A variável pontosRestantes terá o valor 0 após a execução
da linha 19.

4) Considere o código abaixo e escolha a alternativa correta:

1| class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|
5|   val nome = nome
6|   var pontosDeVida = pontosDeVida
7|   var pontosDeAtaque = pontosDeAtaque
8|
9|   override fun toString(): String {
10|    return “”” Dados do herói:
11|   nome.......: $nome
12|   ptsVida....: $pontosDeVida
13|    ptsAtaque..: $pontosDeAtaque “””
14|  }
15| }
16|
17| fun main() {
18|   var heroi = Heroi(“Cron”, 17.0, 23.0)
19|  println(heroi)
20| }

6-19
(  ) -a) Existe um erro na linha 9 pois a palavra-chave override, não
existe na linguagem Kotlin.

EX ER C ÍC IO S PR O PO STO S
(  ) -b) Ao executar o programa a mensagem mostrada na tela será
algo similar a: Heroi@5a07e868, que é o endereço de me-
mória do objeto herói.
(  ) -c) A saída do programa na tela será:
Dados do herói:
Nome.......: Cron
PtsVida....: 17.0
PtsAtaque..: 23.0
(  ) -d) A sobrecarga do método toString está errada na classe Herói
pois este método recebe uma String como parâmetro.
(  ) -e) Na linha 19 devemos passar como parâmetro a classe Herói
e não uma instância dela.

5) Sobre o conceito de herança, escolha a alternativa correta:

(  ) -a) Quando herdamos os atributos e métodos de uma classe não


precisamos marcar ela com o modificador open, pois todas
as classes da linguagem Kotlin já são open por padrão.
(  ) -b) Devemos marcar a classe da qual herdamos os atributos e
propriedades com o modificador open, e na declaração da
nova classe utilizar o símbolo dois pontos para indicar de
qual classe iremos fazer a herança.
(  ) -c) Não podemos herdar atributos no processo de herança.
(  ) -d) Não podemos herdar métodos no processo de herança.
(  ) -e) N,d,a.

6) Considere o código abaixo e escolha a alternativa correta:

1| open class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|  fun sofreDano(pontosDeDano: Doub-
le): Double {
5|    pontosDeVida = pontosDeVida - pontosDeDano

6-20
6|    if (pontosDeVida <= 0) {
7|    println(“O Herói morreu.”)

EX ER C ÍC IO S PR O PO STO S
8|   }
9|   return pontosDeVida
10|  }
11| }
12|
13| class HeroiMagico(nome: String,
14| pontosDeVida: Double,
15| pontosDeAtaque: Double,
16| pontosDeMagia: Double = 30.0) :
17| Heroi(nome,
18| pontosDeVida,
19| pontosDeAtaque) {
20|
21|   var pontosDeMagia = pontosDeMagia
22|   fun usaMagia(consumoDeMagia: Double) {
23|    pontosDeMagia = pontosDeMa-
gia - consumoDeMagia
24|    if (pontosDeMagia > 0 ) {
25|    println(“Feitiço lançado.”)
26|    } else {
27|    println(“Sem magia.”)
28|   }
29|  }
30| }
31|
32| fun main() {
33|  var heroiMagico = HeroiMagico(“Cron”,
17.0, 23.0)
34|  heroiMagico.usaMagia(10.0)
35|  heroiMagico.usaMagia(40.0)
36|  heroiMagico.sofreDano(30.0)
37| }

6-21
(  ) -a) Durante a execução do programa um erro vai acontecer pois
o método usaMagia depende do atributo pontosDeMagia

EX ER C ÍC IO S PR O PO STO S
que não possui valor nenhum pois não foi passado como pa-
râmetro no construtor da classe.
(  ) -b) A função usaMagia, não poderá ser usada pois não foi mar-
cada como public.
(  ) -c) A classe HeroiMagico deverá ser ter o modificador open,
para que ela possa herdar corretamente os atributos e mé-
todos da classe Herói.
(  ) -d) O código vai gerar um erro de compilação pois o atributo
pontosDeMagia não é opcional.
(  ) -e) O programa executa sem erros e a saída dele será:
Feitiço lançado.
Sem magia.
O Herói morreu.

7) Considere o código abaixo e escolha a alternativa correta:

1| open class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|
5|   val nome = nome
6|   var pontosDeVida = pontosDeVida
7|   var pontosDeAtaque = pontosDeAtaque
8|
9|   fun sofreDano(pontosDeDano: Double){
10|   pontosDeVida = pontosDeVida - pontosDeDano
11|    if pontosDeVida <= 0 {
12|    println(“O Herói morreu.”)
13|   }
14|   return pontosDeVida
15|  }
16| }

6-22
(  ) -a) O código acima não vai compilar pois existe apenas um erro
na linha 9.

EX ER C ÍC IO S PR O PO STO S
(  ) -b) O código acima não vai compilar, pois na linha 9 é necessá-
rio declarar que o método retorna o tipo Double. E na linha
1 precisamos remover a palavra chave open
(  ) -c) Existe apenas um erro neste código.
(  ) -d) Na linha 11 é necessário declarar a expressão condicional en-
tre parênteses.
(  ) -e) Para que o código compile, precisamos adicionar o tipo de
retorno do método na linha 9 e na linha 11, é necessário co-
locarmos a expressão condicional entre parênteses.

8) Considere o código abaixo e escolha a alternativa correta:

17| open class Heroi(nome: String,


18| pontosDeVida: Double,
19| pontosDeAtaque: Double) {
20|
21|   val nome = nome
22|   var pontosDeVida = pontosDeVida
23|   var pontosDeAtaque = pontosDeAtaque
24|
25|   fun toString(): String {
26|    return “”” Dados do herói:
27|   nome.......: $nome
28|   ptsVida....: $pontosDeVida
29|   ptsAtaque..: $pontosDeAtaque
30|  }
31|
32|  fun sofreDano(pontosDeDano: Double): Double {
33|    pontosDeVida = pontosDeVida -
pontosDeDano
34|    if (pontosDeVida <= 0) {
35|    println(“O Herói morreu.”)
36|   }

6-23
37|
38|  }

EX ER C ÍC IO S PR O PO STO S
39| }

(  ) -a) O código acima não compila, pois está faltando apenas a pa-
lavra-chave override, na declaração do método toString.
(  ) -b) O código acima não compila, pois na linha 16 o método so-
freDano foi definido como retornando o tipo Double, porém
neste método, não foi definido nenhum valor de retorno.
(  ) -c) Para que o código compile, falta apenas colocar na linha 13
três aspas duplas.
(  ) -d) Para que este código compile, precisamos adicionar na linha
13, três aspas duplas, na linha 9 devemos marcar o método
toString com a palavra-chave override e por fim colocar a
palavra-chave return e na sequência um valor de retorno no
método sofreDano.
(  ) -e) N,d,a.

9) Considere o código abaixo e escolha a alternativa correta:

1| open class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|
5|   val nome = nome
6|   var pontosDeVida = pontosDeVida
7|   var pontosDeAtaque = pontosDeAtaque
8|
9|   override fun toString(): String {
10|    return “”” Dados do herói:
11|   nome.......: $nome
12|   ptsVida....: $pontosDeVida
13|    ptsAtaque..: $pontosDeAtaque “””
14|  }
15|

6-24
16|  open fun sofreDano(pontosDeDano: Doub-
le): Double {

EX ER C ÍC IO S PR O PO STO S
17|    pontosDeVida = pontosDeVida - pontosDeDano
18|    if (pontosDeVida <= 0) {
19|    println(“O Herói morreu.”)
20|   }
21|   return pontosDeVida
22|  }
23| }
24|
25| class HeroiMagico(nome: String,
26| pontosDeVida: Double,
27| pontosDeAtaque: Double,
28| pontosDeMagia: Double = 30.0) :
29| Heroi(nome,
30| pontosDeVida,
31| pontosDeAtaque) {
32|
33|   var pontosDeMagia = pontosDeMagia
34|   fun usaMagia(consumoDeMagia: Double) {
35|    pontosDeMagia = pontosDeMa-
gia - consumoDeMagia
36|    if (pontosDeMagia > 0 ) {
37|    println(“Feitiço lançado.”)
38|    } else {
39|    println(“Sem magia.”)
40|   }
41|  }
42|
43|  override fun sofreDano(pontosDeDano:
Double): Double {
44|   super.sofreDano(pontosDeDano)
45|    pontosDeMagia = pontosDeMagia + pon-
tosDeDano * 0.1
46|   return pontosDeVida

6-25
47|  }
48| }

EX ER C ÍC IO S PR O PO STO S
49|
50| fun main() {
51|  var heroiMagico = HeroiMagico(“Cron”,
57.0, 23.0)
52|  println(“Pontos de magia ${heroiMa-
gico.pontosDeMagia}”)
53|  heroiMagico.sofreDano(30.0)
54|  println(“Pontos de magia ${heroiMa-
gico.pontosDeMagia}”)
55| }

(  ) -a) O código não compila, pois o método sofreDano não pode


ser sobrescrito.
(  ) -b) O código acima não modifica os pontos de magia quando o
herói sobre dano.
(  ) -c) O código acima dá 10% de magia independente do dano que
o herói sofre.
(  ) -d) O código acima dá 10% de magia calculados sobre os pontos
de dano.
(  ) -e) As linhas 45 e 46 podem ser removidas do código pois nunca
serão executadas.

10) Considere o código abaixo e escolha a alternativa correta:

1| open class Heroi(nome: String,


2| pontosDeVida: Double,
3| pontosDeAtaque: Double) {
4|   val nome = nome
5|   var pontosDeVida = pontosDeVida
6|   var pontosDeAtaque = pontosDeAtaque
7|   override fun toString(): String {
8|    return “”” Dados do herói:
9|   nome.......: $nome

6-26
10|   ptsVida....: $pontosDeVida
11|    ptsAtaque..: $pontosDeAtaque “””

EX ER C ÍC IO S PR O PO STO S
12|  }
13| }
14|
15| class HeroiMagico(nome: String,
16| pontosDeVida: Double,
17| pontosDeAtaque: Double,
18| pontosDeMagia: Double = 30.0) :
19| Heroi(nome,
20| pontosDeVida,
21| pontosDeAtaque) {
22|   var pontosDeMagia = pontosDeMagia
23|   override fun toString(): String {
24|    var dadosHeroi = super.toString()
25|    dadosHeroi = dadosHeroi + “\n ptsMa-
gia...: $pontosDeMagia”
26|    dadosHeroi = dadosHeroi + “\n Classe:
Herói Mágico”
27|   return dadosHeroi
28|  }
29| }
30|
31| fun main() {
32|   var heroiMagico = HeroiMagico(
33|  “Cron”,
34|  57.0,
35|  43.0,
36|   pontosDeMagia = 70.0)
37|  println(heroiMagico)
38| }

(  ) -a) O programa vai dar um erro, pois não podemos sobrescrever


o mesmo método duas vezes.
(  ) -b) A saída do programa será:

6-27
Dados do herói:
Nome.......: Cron

EX ER C ÍC IO S PR O PO STO S
PtsVida....: 57.0
PtsAtaque..: 43.0
(  ) -c) A saída do programa será:
Dados do herói:
Nome.......: Cron
PtsVida....: 57.0
PtsAtaque..: 43.0
PtsMagia...: 30.0
Classe: Herói Mágico
(  ) -d) O programa não compila, pois o parâmetro pontosDeMagia
não pode ser diferente de 30.
(  ) -e) A saída do programa será:
Dados do herói:
nome.......: Cron
ptsVida....: 57.0
ptsAtaque..: 43.0
ptsMagia...: 70.0
Classe: Herói Mágico

6-28
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 4:
PRIMEIRO APLICATIVO:
ÁLCOOL OU GASOLINA

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Nesta unidade vamos desenvolver um aplicativo que vai mos-


trar ao usuário qual combustível é mais vantajoso. Durante o
desenvolvimento deste aplicativo iremos ver conceitos sobre Ac-
tivity e o desenvolvimento do layout de uma tela.

Ótimos estudos!

Conteúdos da Unidade:
Definição e criação de layouts, O arquivo activity_main.
xml, o Editor de layout do Android Studio, Definição de Cons-
traintLayout, TextView, EditText, Definindo a MainActivity, O
método onCreate, Definição de Enum.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 7:
DEFININDO O LAYOUT
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
7.1 Introdução
Agora que já temos alguma base na linguagem Kotlin, pode-
mos começar a desenvolver o primeiro aplicativo para a plataforma
Android. No Brasil, os carros bi-combustíveis são a maioria, mas
quando vamos abastecer, fazemos aquela conta básica dividindo o
preço do litro do álcool pelo preço do litro da gasolina.
Se o valor desta divisão for menor que 0.7 então dizemos que
o álcool é mais indicado, caso contrário, se o valor desta divisão for
maior ou igual a 0.7 então dizemos que a gasolina é mais indicada.
Veja que para fazermos este cálculo, precisaremos de forne-
cer ao aplicativo os valores dos combustíveis, ou seja, precisamos
de dois campos que aceitem esses valores.
Precisaremos também de um lugar na tela para mostrar o
resultado, ou seja, um lugar para mostrarmos uma frase informan-
do qual combustível é mais indicado em termos econômicos para
ser comprado.

7.2 Criando o projeto Melhor Combustível


Vamos começar criando um novo projeto, para isso abra o
Android Studio e crie um novo projeto do tipo Empty Activity.
No campo Name, vamos dar o nome de Melhor Combustivel.
No campo Package name, vamos colocar o texto com.
primeiro.melhorcombustivel. Para o campo Save loca-
tion, escolha uma pasta no seu computador a qual você se lembre
posteriormente, pode manter a que o Android Studio coloca como
padrão, desde que você se lembre.

7-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
Não se esqueça de marcar a linguagem como Kotlin, e pode
deixar como padrão o Minimum SDK. Após entrar com as informa-
ções descritas acima, clique no botão Finish.
Neste instante o Android Studio, mudará para a tela de pro-
jeto e poderemos começar a desenvolver o nosso aplicativo.

7.3 Criando o Layout do projeto


Inicialmente vamos começar o projeto definindo seu Layout,
para isso utilize o navegador dos itens de projeto que fica no lado
esquerdo da tela do Android Studio, e dentro da pasta app, abra
a pasta res, que é onde ficam os recursos do projeto, depois vá
até a pasta layout, que é onde ficam armazenados os arquivos
de layout do projeto e selecione o arquivo activity_main.xml.
Se os passos foram seguidos corretamente, você deverá estar
vendo a tela de edição de layout do Android Studio.

Figura 7-1: Editor de Layout.

Agora podemos começar a construir o layout da aplicação,


inicialmente vamos remover esse elemento do tipo TextView, que

7-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
possui o texto “Hello World!”, para isso escolha este elemento no
editor e aperte a tecla delete.
Com este elemento removido vamos começar adicionando
um elemento do tipo TextView, este elemento é responsável por
mostrar um texto na tela do dispositivo, vamos usar este Text-
View para mostrar o texto “Preço do Álcool”.
Para isso arraste o elemento TextView para a tela de
layout, note que o elemento raiz do layout por padrão é do
tipo ConstraintLayout.
Esse componente é invisível e provê ao layout um sistema de
restrições para o posicionamento dos elementos na tela, no caso
do elemento TextView que adicionamos vamos, colocar uma res-
trição que centraliza este componente horizontalmente na tela,
para isso clique com o botão direito, escolha a opção Center, e
escolha na sequência o item Horizontally, como mostrado na
figura abaixo:

7-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
Figura 7-2: Adicionando restrições.

Após definirmos a restrição de centralização horizontal, é


hora de definirmos uma restrição vertical, que cria um espaçamen-
to do elemento com o topo da tela, para isso, selecione o compo-
nente TextView, e na aba da direita do Android Studio, chamada
de Attributes.
Expanda o grupo Layout, e clique no botão do sinal positivo
no topo da imagem do quadrado. Como mostrado na figura abaixo:

7-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
Figura 7-3: Adicionando restrições verticais.

Automaticamente o Android Studio sugere um valor para


essa restrição, este valor é baseado na posição do componente
TextView dentro do componente ConstraintLayout, no caso
do exemplo foi 62.
Não se preocupe agora, se esse valor não for o mesmo no seu
editor, ao final, vamos ajustar todos os valores das restrições para
obtermos um layout amigável.
Feito isso, vamos aumentar um pouco mais o tamanho da
fonte do texto para isso modifique a propriedade textSize, para
o valor 20sp.
Agora precisamos de um componente para que o usuário en-
tre com o valor do preço do álcool, vamos então adicionar no nosso
layout um componente do tipo EditTextNumberDecimal, para
isso escolha a opção text no grupo chamado Palette.
No lado esquerdo da tela do Android Studio, na lista escolha
o componente chamado Number (Decimal), e arraste para a tela
de layout.

7-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
Como feito anteriormente adicione uma restrição de cen-
tralização horizontal e outra restrição vertical da mesma maneira
como foi feito com o componente TextView.
Vamos modificar mais algumas propriedades do Edit-
TextNumberDecimal, para melhorar o layout, vamos centralizar
o texto do campo, para isso selecione este componente e no lado
direito, no grupo All Attributes, expanda a opção gravity, e
marque a opção center_horizontal.
Por fim, vamos modificar o atributo id, este atributo é o
identificador do elemento EditTextNumberDecimal, e será
utilizado no momento em que for necessário pegarmos o valor do
campo para efetuarmos a regra de negócio. Este campo aparece
no grupo Attributes, logo no topo, modifique seu conteúdo
para campoValorAlcool.
Ao final desta etapa o layout deve estar parecido com o da fi-
gura abaixo, mas sinta-se à vontade para experimentar as diversas
opções, mude a fonte do texto,o tamanho a cor, quanto mais experi-
mentos você fizer, mais familiarizado você ficará com a ferramenta.

Figura 7-4: Construção parcial do Layout.

Agora precisaremos de mais dois elementos como estes, para


representar as informações do preço da gasolina. Vamos então

7-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
arrastar mais um elemento do tipo TextView, mudar o atributo
text para Gasolina e o atributo textSize para 20sp.
Feito isso, vamos colocar as restrições de Layout, vamos
inicialmente colocar a restrição de centralização horizontal e a res-
trição de margem superior.
Por fim, temos que adicionar mais um elemento do tipo
EditTextNumberDecimal, que será onde o usuário vai entrar o
valor do preço da gasolina.
Devemos mudar o campo id para que possamos poste-
riormente, pegar o valor deste campo. Vamos então colocar o va-
lor campoValorGasolina.
Da mesma maneira como feito anteriormente, vamos marcar
no atributo gravity a opção center_horizontal. Ao final des-
tes dois passos teremos o seguinte resultado:

Figura 7-5: Layout com os dois campos necessários.

Falta apenas mais dois elementos para terminarmos o layout


da aplicação, o primeiro deles será do tipo Button, ou seja, um

7-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
botão, que quando for pressionado, irá fazer o cálculo da divisão
do preço do álcool pelo preço da gasolina.
Para adicionar este botão, selecione no grupo Palette no
lado esquerdo da tela do Android Studio, a opção Buttons, depois
na lista da direita escolha a opção Button, e arraste para o editor
de layouts.
Inicialmente vamos mudar o título do botão, para isso se-
lecione o elemento na tela de layout e no canto direito da tela do
Android Studio escolha a opção text, mude o texto deste campo
para CALCULAR. Para o botão também precisaremos mudar o texto
do id, neste caso, modifique o valor para botaoCalcular.
Agora vamos adicionar as restrições de layout, uma restrição
para centralizar o botão horizontalmente e outra para termos uma
margem superior do campo texto que será utilizado para a entrada
do preço da gasolina.
O último elemento que vamos adicionar ao layout do nosso
aplicativo será novamente do tipo TextView, para isso selecione
no grupo Palette, a opção Common, e na lista adjacente, arras-
te o item TextView para o editor de layout, logo abaixo do bo-
tão calcular.
Edite o atributo text deste componente para o valor: Com-
bustível mais vantajoso. Modifique também o atributo
textSize para 20sp.
Como utilizaremos este componente para exibir qual com-
bustível vale mais apenas, precisaremos mudar o valor do cam-
po id, para um valor mais amigável. Modifique então o valor
para textCombustivel.

7-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
Chegou a vez de adicionarmos as restrições de layout para
este componente, vamos novamente adicionar uma restrição de
centralização horizontal e outra para a margem superior.
Por fim o layout do nosso aplicativo que mostra qual com-
bustível é mais vantajoso deverá ficar assim:

Figura 7-6: Layout completo do aplicativo

Agora temos o layout do aplicativo completamente definido,


você pode rodar o aplicativo e ver que consegue entrar com os valo-
res nos campos, mas quando clica no botão calcular nada acontece.
Isso acontece, pois não implementamos a lógica que fará o
cálculo de qual combustível é o mais vantajoso. Para isso deveremos

7-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 7

D EFIN IN D O O LAYO UT
escrever o código na linguagem Kotlin, no arquivo MainActivi-
ty, veremos isso no próximo capítulo.

7-12
 EXERCÍCIOS PROPOSTOS

1) Em qual pasta do projeto ficam armazenados os arquivos de layout?

(  ) -a) App/java/res
(  ) -b) Java/app/res
(  ) -c) App/res/layout
(  ) -d) App/res/drawable
(  ) -e) App/res/values

2) Para que serve o arquivo activity_main.xml ?

(  ) -a) Para armazenar o código escrito em Kotlin da que determina


o layout da main activity.
(  ) -b) Para armazenar o código xml que define o layout da main
activity.
(  ) -c) É um arquivo sem utilidade e deverá ser deletado após a
criação do projeto.
(  ) -d) Armazena apenas a parte gráfica do layout em formato
binário.
(  ) -e) O arquivo activity_main pode conter o layout de uma ou
mais activities.

3) Para que serve um elemento de layout do tipo TextView?

(  ) -a) Para criar um elemento que vai representar um campo texto


na tela.
(  ) -b) Para criar um elemento que vai representar um botão na tela.
(  ) -c) Este elemento cria um espaço na tela para que um texto seja
exibido.
(  ) -d) Este elemento não existe na plataforma Android.
(  ) -e) Este elemento cria um espaço na tela para que uma imagem
seja exibida.

7-13
4) Para que serve um elemento de layout do tipo EditText ?

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Este elemento não existe na plataforma Android.
(  ) -b) Para criar um elemento que vai representar um campo texto
na tela.
(  ) -c) Para criar um elemento que vai representar um botão na tela.
(  ) -d) Este elemento cria um espaço na tela para que uma imagem
seja exibida.
(  ) -e) N.d.a.

5) Para que serve o componente ConstraintLayout ?

(  ) -a) Para gerenciar o posicionamento dos componentes seguin-


do uma lógica baseada em uma matriz de linhas e colunas.
(  ) -b) Para gerenciar o posicionamento dos componentes seguin-
do uma lógica de pilha que pode ser tanto vertical quanto
horizontal.
(  ) -c) Para gerenciar o posicionamento dos componentes seguin-
do um mecanismo de restrições.
(  ) -d) Devemos remover este componente já que ele não será uti-
lizado para nada.
(  ) -e) Este componente é utilizado para definir que a cor de fundo
da tela seja branca.

6) Escolha a opção abaixo que descreve como devemos centralizar horizon-


talmente um elemento na tela.

(  ) -a) Devemos utilizar um componente do tipo LinearLayout.


(  ) -b) Devemos clicar com o botão direito do mouse no elemento
que queremos centralizar e escolher a opção Show Baseline.
(  ) -c) Na tela de desenho de layout, devemos escolher o compo-
nente e clicar com o botão direito do mouse, e no menu que
vai abrir escolher a opção Refactor.
(  ) -d) Na tela de desenho de layout, devemos escolher o compo-
nente e clicar com o botão direito do mouse, e no menu que
vai abrir escolher a opção Center, e logo em seguida a opção
Horizontally.

7-14
(  ) -e) Na tela de desenho de layout devemos clicar com o botão di-
reito no elemento que vai ser centralizado e escolher a opção

EX ER C ÍC IO S PR O PO STO S
Refactor.

7) Qual é o propósito do atributo id de um elemento do layout

(  ) -a) Este atributo vai armazenar qual é o nome da cor do plano


de fundo deste objeto.
(  ) -b) Este atributo vai armazenar o tamanho do texto que vai ser
exibido por este elemento.
(  ) -c) Este atributo não é necessário quando queremos acessar um ele-
mento definido no layout por meio do código escrito em Kotlin.
(  ) -d) É necessário sabermos qual é o valor do atributo id quando
queremos ter uma referência para este elemento no código
Kotlin. Como por exemplo quando queremos pegar o valor
que o usuário digitou no elemento do tipo EditText.
(  ) -e) Às vezes é necessário termos uma referência de um elemen-
to de layout em outro arquivo de layout, para isso fazemos
uso do atributo id.

8) Para que serve um elemento de layout do tipo Button ?

(  ) -a) Este elemento não existe na plataforma Android.


(  ) -b) Para criar um elemento que vai representar um botão na tela.
(  ) -c) Este elemento cria um espaço na tela para que uma imagem
seja exibida.
(  ) -d) Este elemento é utilizado para se criar um campo texto para
o usuário entrar com alguma informação.
(  ) -e) N.d.a.

9) Para que serve o atributo chamado text do componente de layout do tipo


TextView?

(  ) -a) É neste atributo que vamos definir o nome do componen-


te que será utilizado posteriormente para que possamos ter
uma referência deste elemento no código.
(  ) -b) O atributo text não existe nos elementos do tipo TextView.

7-15
(  ) -c) É o texto que está armazenado no atributo text que será exi-
bido na tela onde o elemento TextView foi definido.

EX ER C ÍC IO S PR O PO STO S
(  ) -d) O atributo text do elemento TextView deve ter o mesmo
valor do atributo id, senão um erro vai acontecer durante a
compilação.
(  ) -e) Não podemos modificar o atributo text do elemento Text-
View por meio do código Kotlin.

10) Como criamos um novo projeto Android com uma Empty Activity utilizan-
do o Android Studio?

(  ) -a) Devemos criar toda a estrutura de pastas manualmente ape-


nas seguindo a documentação pois o Android Studio não
tem permissão do sistema operacional para fazer isso.
(  ) -b) Não é necessário criar a estrutura de pastas, porém devemos
configurar os arquivos do gradle manualmente.
(  ) -c) Devemos apenas criar o arquivo activity_main.xml pois o
Android Studio não cria este arquivo.
(  ) -d) Devemos criar o arquivo MainActivity.kt
(  ) -e) No Android Studio devemos clicar na opção File, depois em
New Project e por fim escolher a opção Empty Activity.

7-16
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 8:
CODIFICANDO A ACTIVITY
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
8.1 Introdução
É no arquivo MainActivity que deveremos escrever a lógi-
ca do nosso aplicativo, veja que é neste arquivo que a classe Mai-
nActivity foi definida.
Nos capítulos anteriores explicamos como o mecanismo de
herança funciona na programação orientada a objetos, este concei-
to é utilizado aqui, pois a classe MainActivity, herda as proprie-
dades da classe AppCompatActivity.
Note que o método onCreate está marcado pelo modifica-
dor override, ou seja, o código que escrevemos neste método
será executado assim que o aplicativo for iniciado.

8.2 Referência aos campos de preço


Inicialmente vamos definir as variáveis que servirão de refe-
rência para os campos onde os valores dos preços dos combustíveis
serão entrados pelo usuário do aplicativo.
Para isso vamos definir no início da classe as seguintes variáveis:

9| class MainActivity : AppCompatActivity() {


10|
11|  lateinit var campoPrecoGasolina: EditText
12|   lateinit var campoPrecoAlcool: EditText
13|  :
14|  :
15|
16| }

8-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
Na linha 9 mostramos a definição da classe MainActivity,
e logo na linha 11 definimos a variável campoPrecoGasolina,
definimos esta variável mutável como sendo do tipo EditText e
marcamos a sua definição com a palavra-chave lateinit. Na se-
quência fazemos o mesmo criando a variável campoPrecoAlco-
ol, que também é do tipo EditText.
O modificador lateinit diz ao compilador que esta vari-
ável será inicializada mais a frente, e isso vai acontecer no novo
método que iremos criar chamado defineCampos, como mostrado
logo abaixo.

21| private fun defineCampos() {


22|  
campoPrecoGasolina = findViewById<Edit-
Text>(R.id.campoValorGasolina)
23|  
campoPrecoAlcool = findViewById<Edit-
Text>(R.id.campoValorAlcool)
24| }

Na linha 21 definimos o método chamado defineCam-


pos, marcamos a definição deste método com o modificador
private, pois este método será utilizado apenas dentro da
classe MainActivity.
Logo abaixo, na linha 22, armazenamos na variável campo-
PrecoGasolina, uma referência para o elemento gráfico que foi
definido no layout e que recebe o preço do combustível gasolina.
Para isso fizemos o uso da função findViewById, como o pró-
prio nome diz esta função procura no layout o elemento que possui
o id que ela recebe como parâmetro, veja que neste caso utilizamos
o valor do parâmetro como sendo R.id.campoValorGasolina,

8-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
o Android, transforma o atributo do tipo texto chamado id, que
utilizamos no editor de layout para colocar o nome do elemento
em uma constante que é acessada por meio da classe R.
Outro ponto importante é que passamos o tipo do elemento
que estamos procurando entre os símbolos < e >, neste caso como
procuramos um elemento do tipo EditText escrevemos <Edit-
Text>, por meio desta notação é possível passar para um método
um tipo qualquer como parâmetro, esta propriedade faz parte do
conceito de Generics, que não será escopo deste material.
Por fim teremos uma referência do elemento ao elemento
gráfico que possui o valor do preço do combustível do tipo gasoli-
na, fizemos tudo isso pois precisamos deste valor no cálculo, que
será feito para dizer qual combustível é mais vantajoso.
Na linha 23 fizemos a mesma coisa para o elemento gráfico
que armazena o valor do preço do álcool, utilizamos da mesma ma-
neira o método findViewById, só que desta vez utilizamos como
parâmetro a constante R.id.campoValorAlcool, e armazena-
remos esta referência na variável
Por fim, após a execução do método defineCampos, teremos
as duas variáveis campoPrecoGasolina, e campoPrecoAlco-
ol, as quais utilizaremos para pegar os valores para o cálculo.

8.3 Definição do enum Combustivel


A maioria das linguagens de programação modernas dispo-
nibilizam o conceito de enumeração, que nada mais é do que criar-
mos uma classe de atributos que possuem um valor fixo, como no
caso do nosso aplicativo onde temos dois valores fixos que são os

8-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
nomes dos combustíveis, ou seja Álcool e Gasolina. Veja logo abai-
xo como fica definido este Enum.

52| enum class Combustivel(val nome: String) {


53|  GASOLINA(“Gasolina”),
54|  ALCOOL(“Álcool”);
55|
56|   override fun toString(): String {
57|   super.toString()
58|   return nome
59|  }
60| }

Uma maneira de declararmos uma classe enum no Kotlin, é


utilizarmos a palavra-chave enum, seguida da palavra-chave class.
Na sequência, definimos o nome que será dado a esse ele-
mento, no caso do nosso aplicativo daremos o nome de Combuti-
vel, pois os dois atributos deste enum serão os nomes dos com-
bustíveis usados.
Veja que, logo após o nome do enum, usamos um construtor
que recebe um único parâmetro, chamado nome e que é do tipo
String, fizemos desta maneira para poderemos ter representa-
ções do tipo String, de cada um dos atributos do enum, isso será
útil quando formos construir a mensagem que mostrará qual com-
bustível é mais vantajoso.

8-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
Logo na linha 53 definimos o atributo GASOLINA, passando
como parâmetro a String Gasolina, e na sequência o atributo
ALCOOL, com a String, Álcool como parâmetro.
Para que possamos utilizar as representações do tipo
String dos atributos do enum, precisamos de sobrecarregar o
método toString.
Por isso, na linha 56 utilizamos a palavra-chave override,
e escrevemos o nome do método toString, informando que o seu
retorno é String, e no corpo do método apenas retornamos o va-
lor do atributo nome da classe enum.
Com isso temos tudo o que precisamos para definir a função
que vai fazer o cálculo do combustível mais indicado. Veremos isso
logo em seguida.

8.4 Criando o método de cálculo


Agora vamos definir o método que vai receber o preço dos
dois combustíveis e irá retornar um objeto do tipo Combustivel,
ou seja um objeto do tipo enum que definimos anteriormente, indi-
cando qual combustível é o mais vantajoso, veja abaixo, como esse
método vai ficar:

41| private fun


42| calcularMelhorCombustivel(precoGasoli-
na: Double,
43| precoAlcool: Double):Combustivel {
44|   val fatorEscolha = 0.7
45|   val proporcao = precoAlcool / precoGasolina

8-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
46|   if (proporcao < fatorEscolha) {
47|   return Combustivel.ALCOOL
48|   } else {
49|   return Combustivel.GASOLINA
50|  }
51| }

Começando na linha 41 definimos o nome do método que


será calcularMelhorCombustivel, marcamos este método
com o modificador private, pois não utilizaremos ele fora da
classe MainActivity, e definimos seus dois parâmetros pre-
coGasolina do tipo Double e precoAlcool também do tipo
Double, pois como estamos tratando de valores monetários pre-
cisamos levar em consideração pelo menos duas casas decimais.
Nesta mesma linha definimos que o retorno deste método
será do tipo Combustível, que é o tipo enum que definimos ante-
riormente, e que possui dois atributos, que representam os nomes
dos combustíveis.
Desta maneira baseado no cálculo do combustível mais
vantajoso, um desses valores será escolhido e retornado por
esse método, para compor a mensagem que indica qual é o me-
lhor combustível.
A fórmula que vamos utilizar para determinar qual o com-
bustível é mais vantajoso é a seguinte, se a divisão do valor do pre-
ço do álcool pelo valor do preço da gasolina for menor que 0.7
então, indicaremos o álcool como sendo o combustível mais vanta-
joso, caso contrário será a gasolina o combustível mais vantajoso.

8-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
É considerado uma boa prática no desenvolvimento de sof-
tware evitarmos usar valores literais diretamente na lógica, por
isso na linha 43, criamos a variável imutável chamada fatorEs-
colha, e atribuímos a essa variável o valor 0.7.
Na sequência, na linha 44, efetuamos a divisão entre os parâ-
metros precoAlcool e precoGasolina, o valor desta divisão será
armazenado na variável imutável que chamamos de proporcao.
Agora precisamos verificar se o valor da variável propoção,
é menor que o valor armazenado em fatorEscolha, fizemos isso
na linha 45, utilizando a expressão condicional determinada após
a palavra-chave if.
Caso o valor da expressão condicional for true, então o có-
digo da linha 46 será executado, e o valor retornado será o atributo
ALCOOL da classe enum Combustível. Caso contrário, se o valor
da expressão da linha 45, retornar o valor false, então o código
da linha 48 será executado, ou seja, o valor retornado por esse mé-
todo será o atributo GASOLINA, da classe enum Combustível.
Com isso, já temos um método que recebe os preços da ga-
solina e do álcool e retorna qual combustível é o mais vantajoso.

8.5 Criando o método que mostra o resultado


Agora o aplicativo já é capaz de calcular qual é o combustí-
vel mais vantajoso, precisamos escrever um método que cria uma
mensagem amigável para o usuário, indicando qual é o combustí-
vel mais vantajoso. Veja abaixo como ficou este método.

36| private fun mostraResultado(resulta-


do: Combustivel) {

8-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
37|  
val resultadoTextView = findViewById<-
TextView>(R.id.textCombustivel)
38|  resultadoTextView.text = “O Combustível
indicado é ${resultado.toString()}”
39| }

Inicialmente na linha 36, definimos o nome do método como


sendo mostraResultado, este método, recebe apenas um parâ-
metro, que é do tipo enum Combustível, neste parâmetro já es-
tará qual combustível é o mais indicado.
Novamente vamos usar o método findViewById, mas desta
vez vamos pegar a referência de um objeto do tipo TextView, que
possui o id indicado pela constante R.id.textCombustivel,
este é o elemento que reservamos durante a construção do layout
para mostrarmos a mensagem que indica ao usuário qual é o me-
lhor combustível a ser comprado.
A referência para este elemento ficará armazenada na va-
riável resultadoTextView, e já na linha 38 criaremos a men-
sagem de texto e iremos atribuir ela para a propriedade text do
objeto resultadoTextView.
Veja que utilizamos o método toString para pegar o va-
lor da String que utilizamos na construção do atributo do
tipo Combustível.

8.6 Definindo o clique do botão


Chegou o momento de escrevermos o código que será exe-
cutado quando o usuário apertar o botão Calcular. Este código
deverá pegar os valores dos campos referenciados pelas variáveis

8-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
campoPrecoGasolina e campoPrecoAlcool e usar estes va-
lores como parâmetros para chamar o método calculaMelhor-
Combustivel que vai retornar o atributo do enum Combustí-
vel que representa o combustível mais vantajoso.
Feito isto precisamos exibir ao usuário uma mensagem que
utiliza este valor, para isso faremos uma chamada para o méto-
do mostraResultado. Veja abaixo como ficou o código do mé-
todo defineBotao:

26| private fun defineBotao() {


27|  
val botaoCalcular = findViewById<But-
ton>(R.id.botaoCalcular)
28|   botaoCalcular.setOnClickListener {
29|   
val precoAlcool = campoPrecoAlcool.
text.toString().toDouble()
30|   
val precoGasolina = campoPrecoGasoli-
na.text.toString().toDouble()
31|   
val combustivel = calcularMelhorCom-
bustivel (precoGasolina,precoAlcool)
32|   mostraResultado(combustivel)
33|  }
34| }

Inicialmente na linha 26 definimos o método chamado de-


fineBotao, marcamos o método com o modificador private,
pois ele será apenas utilizado dentro desta classe, após o nome do
método abrimos e fechamos os parênteses pois este método não
vai receber nenhum parâmetro.

8-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
Lembre-se que estamos escrevendo o método que vai ser
executado quando o botão Calcular for clicado, neste caso, na
linha 27 precisamos pegar a referência do elemento do tipo But-
ton que possui o id, botaoCalcular, que está armazenado em
R.id.botaoCalcular, por isso utilizamos este valor como pa-
râmetro na chamada do método findViewById, e passamos como
tipo o valor Button entre os sinais de menor e maior.
Após a execução desta linha a referência para este elemento
do layout estará disponível na variável botaoCalcular. Veja que
na linha 28 utilizamos o método setOnClickListener de uma
maneira peculiar, veja que logo após o nome do método utilizamos
caractere abre chaves {, escrevemos o código e depois utilizamos o
caractere fecha chaves }, muito código foi simplificado nesta nota-
ção, e pode parecer meio estranho a primeira vista.
Se olharmos no detalhe a definição do método setOnCli-
ckListener, veremos que ele recebe um único parâmetro do tipo
((View) -> Unit), este tipo é uma função lambda, que recebe
como parâmetro um objeto do tipo View, e retorna o tipo Unit.
Em Kotlin, o tipo Unit, indica que a função não possui retorno.
Segundo a linguagem Kotlin, se um método recebe apenas
um parâmetro, e esse parâmetro é uma função, então podemos re-
mover os parênteses.
Outro ponto para simplificarmos é, que se a função lambda
passada como parâmetro não utiliza o seu próprio parâmetro, po-
demos remover todo o lado esquerdo da função, o que sobra então
é apenas o código do corpo da função lambda, ou seja precisamos
apenas usar as chaves e indicar o código da função, que no caso do
exemplo está escrito nas linhas 29 até a 32.
Na linha 29 utilizamos a referência para o campo onde ar-
mazenamos o preço do álcool e acessamos o atributo text, é neste

8-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
atributo que estará o valor do preço do álcool informado pelo usu-
ário, atente ao fato de que o tipo deste atributo é String, ou seja,
precisamos converter este tipo para Double, pois iremos efetuar
uma operação de divisão logo abaixo, e não podemos dividir um
número do tipo String.
O mesmo faremos na linha 30, com a referência ao campo
onde o usuário vai entrar o valor da gasolina, ou seja utilizaremos
atributo text, só que agora da variável campoPrecoGasolina,
converteremos este valor para o tipo Double, e armazenaremos
ele na variável precoGasolina.
Agora que já temos os dois valores dos preços da gasolina e
do álcool, podemos chamar a função calculaMelhorCombus-
tivel, para obter como resposta qual é o combustível mais vanta-
joso, no formato do enum Combustível, e armazenaremos este
valor na variável combustível.
Por fim, utilizaremos a variável combustível como parâ-
metro para o método mostraResultado, feito isso, o objeto do
tipo TextView, será atualizado com a mensagem que informa
qual o combustível é mais vantajoso.

8.7 Finalizando o método onCreate


Para terminarmos este aplicativo falta apenas chamarmos os
métodos defineCampos e o método defineBotao, isso deve ser
feito dentro do método onCreate, pois esse método é chamado
pelo Android assim que o aplicativo é aberto pelo usuário, veja
abaixo como vai ficar o código:

8-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
14| override fun onCreate(savedInstanceSta-
te: Bundle?) {
15|  super.onCreate(savedInstanceState)
16|  setContentView(R.layout.activity_main)
17|   defineCampos()
18|   defineBotao()
19| }

Veja que a palavra chave override, foi usada, pois quere-


mos sobrescrever o método onCreate, isso é necessário para que
o nosso código seja executado na inicialização do aplicativo.
É considerado uma boa prática na programação, sempre fa-
zemos uma chamada ao método original que foi sobrescrito, isso
é feito por meio da palavra chave super, como visto na linha 15.
Na sequência na linha 16, o método setContentView, é
chamado, é neste ponto que todos os elementos definidos no layout
do arquivo activity_main são instanciados e mostrados na tela.
Por fim, nas linhas 17 e 18 chamamos respectivamente os
métodos defineCampos e o método defineBotao.
Agora podemos executar o aplicativo, para isso lembre-se de
clicar no botão com símbolo play em verde, aguarde uns instantes
e o emulador do android vai abrir já com o aplicativo rodando, veja
abaixo como deve ter ficado o resultado final:

8-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 8

C O D IFIC A N D O A ACTI VI TY
Figura 8-1: Aplicativo calcula combustível

8-14
 EXERCÍCIOS PROPOSTOS

1) Qual é o propósito do arquivo MainActivity ?

(  ) -a) Armazenar o código XML do layout da tela do aplicativo.


(  ) -b) Armazenar uma classe do tipo Object chamada de MainActi-
vity que vai controlar o comportamento da primeira tela do
aplicativo.
(  ) -c) Armazenar o código da classe MainActivity que vai herdar as
propriedades da classe AppCompatActivity.
(  ) -d) Podemos deletar este arquivo já que ele apenas foi criado de
maneira automática pelo Android Studio e no nosso projeto
não terá utilidade nenhuma.
(  ) -e) Armazenar o código da classe MainActivity que vai herdar
as propriedades da classe AppCompatActivity, e não vai
sobrescrever o método onCreate que será escrito em outra
classe.

2) Escolha a alternativa correta sobre o método onCreate

(  ) -a) O método onCreate é sempre chamado quando a Activity


está ativa e o aplicativo é enviado para segundo plano.
(  ) -b) Devemos nos certificar que o método onCreate não foi so-
brescrito ou teremos um erro de compilação
(  ) -c) Não é boa prática chamarmos o método onCreate da classe
super no começo do código sobrescrito do método onCreate.
(  ) -d) Devemos sobrescrever o método onCreate e no código so-
brescrito não podemos fazer uma chamada para o método
setContentView, pois a Activity ainda não foi criada.
(  ) -e) Devemos sobrescrever o método onCreate e no código so-
brescrito devemos fazer a chamada para o método setCon-
tentView, passando como parâmetro a constante R.layout.
activity_main, que faz referência ao arquivo activity_main.
xml que possui a definição do layout.

8-15
3) Escolha a alternativa correta sobre o método defineCampos que foi escri-

EX ER C ÍC IO S PR O PO STO S
to na classe MainActivity.

1| private fun defineCampos() {


2|  campoPrecoGasolina = findViewById<Edit-
Text>(R.id.campoValorGasolina)
3|  campoPrecoAlcool = findViewById<Edit-
Text>(R.id.campoValorAlcool)
4| }

(  ) -a) Este método cria em tempo de execução os elementos que


vão representar os campos onde o usuário vai entrar com os
preços da gasolina e do álcool.
(  ) -b) Este método faz uso do método findViewById, passando
como parâmetro entre os sinais maior e menor o tipo que
será retornado e como parâmetro entre os parênteses a
constante que faz referência ao campo. As referências para
os campos serão então armazenadas nas variáveis de classe
campoPrecoGasolina e campoPrecoAlcool.
(  ) -c) O método defineCampos vai gerar um erro de compila-
ção pois não definimos o método findViewById na classe
MainActivity.
(  ) -d) Não podemos marcar o método defineCampos com o modi-
ficador private, pois desta maneira não será possível chamar
este método na classe MainActivity.
(  ) -e) N.d.a.

4) Escolha a alternativa correta sobre o código escrito abaixo:

5| enum class Combustivel(val nome: String) {


6|  GASOLINA(“Gasolina”),
7|  ALCOOL(“Álcool”);
8|
9|   override fun toString(): String {
10|   super.toString()

8-16
11|   return nome
12|  }

EX ER C ÍC IO S PR O PO STO S
13| }

(  ) -a) Não podemos sobrescrever o método toString de uma classe


enum.
(  ) -b) Classes enum são muito utilizadas quando temos um atri-
buto que pode possuir apenas alguns valores fixos, como no
caso do projeto, onde criamos um enum que vai permitir
com que as variáveis deste tipo possuem apenas os valores
Álcool ou Gasolina.
(  ) -c) É uma boa prática não utilizarmos classes do tipo enum e
sim apenas uma String para representar os valores.
(  ) -d) Na linha 6 não podemos chamar o método super.toString
pois desta maneira estaremos gerando um erro de compi-
lação pois o atributo super não foi definido para esta classe.
(  ) -e) Não é necessário na linha 6 utilizarmos a palavra chave
return.

5) Considere o código abaixo e escolha a alternativa correta:

1| private fun calcularMelhorCombusti-


vel(precoGasolina: Double,
2| precoAlcool: Double): Combustivel {
3|   val fatorEscolha = 0.7
4|  val proporcao = precoAlcool / precoGasolina
5|   if (proporcao < fatorEscolha) {
6|   return Combustivel.ALCOOL
7|   } else {
8|   return Combustivel.GASOLINA
9|  }
10| }

(  ) -a) Não podemos marcar este método como private, pois vamos
utilizar ele dentro da classe MainActivity.

8-17
(  ) -b) Não é uma boa prática utilizarmos o valor do tipo enum
como retorno do método.

EX ER C ÍC IO S PR O PO STO S
(  ) -c) Como o tipo da variável proporcao, não foi definido, ele sem-
pre será do tipo Int.
(  ) -d) Este método calcula qual é o combustível mais vantajoso,
retornando como valor o tipo Combustivel que é um enum
com dois valores possíveis ALCOOL ou GASOLINA.
(  ) -e) A variável fatorEscolha não pode ser declarada com o modi-
ficador val.

6) Considere o código abaixo e escolha a alternativa correta:

1| private fun mostraResultado(resulta-


do: Combustivel) {
2|  val resultadoTextView = findViewById<-
TextView>(R.id.textCombustivel)
3|   resultadoTextView.text = “O Combustível
indicado é ${resultado.toString()}”
4| }

(  ) -a) Este método não é necessário pois o valor do resultado será


automaticamente colocado na tela.
(  ) -b) Não podemos definir a variável resultadoTextView com a
palavra chave val pois logo abaixo iremos modificar o texto
desta variável.
(  ) -c) Este método vai pegar o elemento da tela que possui o id
armazenado na constante R.id.textCombustivel, armazenar
uma referência para este componente na variável resulta-
doTextView e por fim modificar o atributo text deste objeto
com o texto referente ao tipo do combustível mais vantajoso.
(  ) -d) Na linha 3 não podemos usar o método toString do parâme-
tro resultado.
(  ) -e) N.d.a.

8-18
7) Considere o código abaixo e escolha a alternativa correta:

EX ER C ÍC IO S PR O PO STO S
1| private fun defineBotao() {
2|  val botaoCalcular = findViewById<But-
ton>(R.id.botaoCalcular)
3|   botaoCalcular.setOnClickListener {
4|    val precoAlcool = campoPrecoAlcool.
text.toString().toDouble()
5|    val precoGasolina = campoPrecoGasoli-
na.text.toString().toDouble()
6|    val combustivel = calcularMelhorCom-
bustivel (precoGasolina,precoAlcool)
7|   mostraResultado(combustivel)
8|  }
9| }

(  ) -a) Não precisamos utilizar o método findViewById para pegar


uma referência do elemento gráfico que representa o botão.
(  ) -b) Nas linhas 4 e 5 não precisamos chamar os métodos toDoub-
le pois o atributo text dos campos já é do tipo Double.
(  ) -c) Na linha 6 deveríamos ter declarado o tipo da variável com-
bustível como sendo o enum Combustível.
(  ) -d) Este método está correto pois define uma a função lambda
que é passada como parâmetro pelo método setOnClickLis-
tener da classe Button. Esta função lambda pega os valores
dos campos e armazena nas variáveis precoAlcool e preco-
Gasolina, na sequência chama o método calcularMelhor-
Combustivel, passando essas duas variáveis como parâme-
tro e por fim mostra na tela o resultado chamando o método
mostraResultado.
(  ) -e) Não podemos chamar o método mostraResultado passando
como parâmetro a variável combustível pois quando decla-
ramos esta variável não definimos seu tipo.

8-19
8) Considere o método onCreate sobrescrito abaixo e escolha a afirmação

EX ER C ÍC IO S PR O PO STO S
correta.

1| fun onCreate(savedInstanceState: Bundle?) {


2|
3|   s e t C o n t e n t V i e w ( R .
layout.activity_main.xml)
4|
5|   defineBotao()
6| }

(  ) -a) Quando sobrescrevemos um método é de boa prática cha-


marmos o método da classe super, já logo nas primeiras li-
nhas, portanto para deixar esse código certo devemos ape-
nas escrever na linha 2 o código super.onCreate.
(  ) -b) Para corrigirmos este método basta apenas adicionarmos a
palavra chave override na linha 1 antes da palavra chave fun.
(  ) -c) Existem apenas dois pontos neste método que devem ser
corrigidos, um deles é remover o .xml da constante na li-
nha 3, e na linha 4 adicionar uma chamada para o método
defineCampos.
(  ) -d) Existem 4 pontos que devem ser modificados no código aci-
ma, primeiro devemos escrever a palavra chave override
na linha 1, em seguida fazer uma chamada para o método
super.onCreate, o terceiro ponto é remover o .xml do parâ-
metro que faz referência ao layout na chamada do método
setContentView e por fim na linha 4 adicionar uma chamada
para o método defineCampos.
(  ) -e) Devemos apenas colocar uma chamada para o método defi-
neCampos na linha 4.

9) Escolha a alternativa que contém o método/atributo utilizado para definir-


mos o código do clique do botão:

(  ) -a) Devemos definir o clique do botão pelo atributo id.


(  ) -b) Devemos definir o clique do botão pelo atributo checkable
do tipo Button.

8-20
(  ) -c) Devemos definir o clique do botão pelo método setOnCli-
ckListener, passando uma outra classe que vai receber o

EX ER C ÍC IO S PR O PO STO S
evento
(  ) -d) Devemos definir o clique do botão pelo método setOnCli-
ckListener, passando uma função lambda que será executa-
da quando o evento acontecer.
(  ) -e) Devemos definir o atributo clickable como true.

10) Escolha a alternativa que contém o método correto que carrega os ele-
mentos do layout definidos no arquivo .xml

(  ) -a) Super.onCreate(savedInstance)
(  ) -b) FindViewById<EditText>(R.id.campoValorGasolina)
(  ) -c) FindViewById<EditText>(R.id.campoValorAlcool)
(  ) -d) SetContentView(R.layout.activity_main.xml)
(  ) -e) SetContentView(R.layout.activity_main)

8-21
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 5:
SEGUNDO APLICATIVO:
LISTA DE COMPRAS

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Nesta unidade desenvolvemos o aplicativo lista de compras,


durante o desenvolvimento deste aplicativo veremos importan-
tes conceitos tais como o uso da RecyclerView, a navegação entre
Activities entre outros.
Veremos também um conceito de arquitetura de aplicativos
muito famoso que é o MVC.

Ótimos estudos!

Conteúdos da Unidade:
Apresentação da arquitetura MVC, Definição do modelo de
dados, Definição da célula da lista de itens, Criação do ViewHol-
der da RecyclerView, Definição e uso de Intents, Criação do
Adapter da RecyclerView, Criação da Activity para inclusão de
novos itens, Criação da Activity para a visualização de itens já
inclusos, Introdução ao arquivo Android Manifest.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 9:
RECYCLERVIEW E RECYCLERADAPTER
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


9.1 Introdução
Neste capítulo iremos desenvolver um novo aplicativo que
servirá de lista de compra. Inicialmente, será apresentado ao usu-
ário uma tela, onde ele poderá incluir itens na lista por meio de
um botão.
Ao clicar no botão, uma nova Activity será chamada, e os
campos nome e quantidade serão apresentados ao usuário, para
que ele registre um novo item e a respectiva quantidade necessá-
ria, feito isso, quando o usuário clicar no botão salvar o item será
adicionado na lista.
Quando o usuário clicar em um elemento da lista, uma nova
Activity será lançada, e o usuário poderá escolher em marcar
este item como comprado, isso fará com que o ícone na lista mude
indicado que agora o item foi comprado.
Será também oferecida ao usuário a opção de remover todos
os itens da lista, por meio de um botão na tela inicial. As imagens
abaixo, mostram o fluxo do aplicativo:

9-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Figura 9-1: Activity inicial Figura 9-2: Activity de Figura 9-3: Activity
com a lista de itens cadastro de itens que onde o usuário
poderá marcar o item
como comprado

9.2 Criando o projeto Lista de Compras


Iniciaremos este capítulo criando o novo projeto no Android
Studio, vamos escolher a opção Empty Activity, pois vamos
iniciar este projeto com apenas uma Activity vazia.
Novamente deveremos preencher algumas informações so-
bre este novo projeto, começamos pelo campo Name, onde vamos
colocar o texto ListaDeCompras, este será o nome do nosso
novo aplicativo.
Na sequência precisamos entrar com o texto para o campo
Package Name, vamos escrever então com.segundo.lista-
decompras. No campo Save Location, escolha um caminho
conhecido no sistema, não se esqueça de escolher, no campo

9-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Language, a linguagem Kotlin, no campo Minimum SDK, pode
escolher o valor 5.0 Lollipop.
Isso significa que o seu aplicativo poderá ser executado em
dispositivos que possuam pelo menos o android versão 5.0, com
nível de 21 de API. Finalize a criação do novo projeto clicando no
botão Finish no canto inferior direito da tela.

9.3 Arquitetura MVC


Neste projeto, vamos seguir um padrão de arquitetura muito
utilizado no desenvolvimento de software que é o MVC - (Mo-
delo, Visualização, Controlador), ou seja dividiremos o
projeto em 3 grupos.

9.3.1 Modelo
Consideremos os elementos do grupo Modelo, como sendo
as entidades que representam os dados que o nosso aplicativo uti-
liza. No caso do aplicativo lista de compras, teremos uma classe
chamada ItemLista, que possuirá os atributos, qtd do tipo Int,
nome do tipo String e comprado do tipo Boolean, que vai indi-
car se o item já foi comprado ou não.
O objetivo do nosso aplicativo é possibilitar ao usuário um
meio de cadastrar novos itens de compra e exibi-los em uma tabela
na tela inicial do aplicativo.

9.3.2 Controlador
Para exibir os dados cadastrados no modelo precisamos
de um elemento que chamaremos de Controlador, no Android,

9-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


podemos considerar as classes do tipo Activity como parte
deste grupo.
É responsabilidade da Activity, acessar os dados que estão
organizados nos modelos e alimentar os elementos de visualização
com estes dados. Também é responsabilidade de uma Activity
pegar o valor de um determinado campo e alimentar o modelo com
estes dados.
Faremos isso neste projeto, onde utilizaremos uma Activi-
ty que vai pegar a quantidade e o nome do item que vai na lista e
armazenar isso no modelo.
Em outra Activity iremos exibir esses mesmos dados num
formato de tabela, como foi mostrado no começo do capítulo.

9.3.3 Visualização
Os controladores, por si só, não exibem os dados e neces-
sitam de elementos gráficos, tais como campos de texto, botões,
listas entre outros para exibir os dados dos modelos.
Ao conjunto destes elementos chamamos de visualização e
no caso da plataforma Android, são comumente descritos em ar-
quivos do tipo xml, que ficam organizados na pasta layout que por
sua vez fica dentro da pasta res.
No caso do aplicativo que vamos desenvolver neste capítulo,
podemos considerar os campos que vão receber o nome e a quan-
tidade dos itens como sendo parte dos elementos de visualização.

9-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


9.4 Escrevendo o modelo de dados
Vamos começar o código do projeto lista de compras pelas
classes do modelo de dados, para manter a organização vamos ini-
cialmente criar um novo pacote chamado modelo, para isso clique
com o botão direito no pacote com.segundo.listadecompras,
selecione a opção new, depois a opção package, e de o nome
de modelo.
Agora, clique com o botão direito do mouse no pacote cha-
mado modelo, e escolha a opção new, Kotlin Class/File, de o
nome de ItemLista. Veja abaixo como será o código desta classe:

1| package com.segundo.listadecompras.modelo
2|
3| data class ItemLista(val qtd: Int,
4| val nome: String,
5| var comprado: Boolean) {
6|
7| }

Para melhorar a organização do aplicativo, criamos esta clas-


se dentro do pacote modelo. A linguagem Kotlin traz o modifica-
dor data para este tipo de classes que representam um modelo
de dados.
Ainda na linha 3, escrevemos a palavra chave class seguida
do nome da classe, que neste caso será ItemLista, pois irá repre-
sentar um item da lista de compras.

9-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Note que logo após a declaração do nome da classe utiliza-
mos o símbolo ( e iniciamos a declaração dos seus atributos, que
serão, qtd do tipo Int que representa a quantidade dos itens que
deverão ser comprados, nome do tipo String, que vai armazenar
o nome do item que deverá ser comprado e o atributo comprado
do tipo Boolean, que indica se o item já foi comprado.
Veja que tanto o atributo qtd quanto o atributo nome, fo-
ram marcados no construtor como val, ou seja, estes atributos
não poderão ser alterados pelo usuário depois da criação do obje-
to, e este é realmente o comportamento que queremos, pois neste
aplicativo não implementarmos a funcionalidade de modificar es-
tes atributos.
Por outro lado, o atributo comprado, foi definido com var,
ou seja, este atributo poderá sim ser modificado, e isso vai aconte-
cer quando o usuário indicar que este item foi comprado.
Ainda no pacote modelo, vamos criar mais uma classe, desta
vez com o nome de ListaDeCompras, esta classe vai possuir um
atributo chamado listaItens, que será uma lista de objetos do
tipo ItemLista, veja abaixo como vai ficar a classe completa:

1| package com.segundo.listadecompras.modelo
2|
3| object ListaDeCompras {
4|
5|   var listaItens = mutableListOf<ItemLista>()
6|
7|   fun adicionarItemNaLista(item: ItemLista) {
8|   listaItens.add(item)

9-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


9|  }
10|
11|   fun removerTodosItens() {
12|   listaItens.clear()
13|  }
14| }

Novamente, na linha 1, declaramos a classe no pacote mo-


delo, pois ainda estamos tratando de uma classe que vai gerenciar
alguns dados no aplicativo.
Desta vez utilizamos o modificador object, esta palavra
chave do Kotlin cria uma classe que é um Singleton, ou seja,
teremos apenas uma instância desta classe durante a execução da
aplicação, e poderemos acessá-la de qualquer Activity, isto será
muito útil, quando por exemplo, formos implementar a Activi-
ty que adicionar um novo item na lista, pois basta fazermos uma
chamada ao método adicionarItemNaLista fazendo uma refe-
rência direta ao nome da classe, você ver isto nas próximas seções.
Logo na linha 5 definimos uma variável mutável que irá ar-
mazenar uma lista de objetos do tipo ItemLista, é essa variável
que vamos utilizar na hora de exibir os itens cadastrados na lista
da MainActivity, como mostrado na introdução deste capítulo,
quando foi mostrado como ficará o aplicativo.
Definimos também nesta classe chamada ListaDeCompras
o método adicionarItemNaLista, veja que este método possui
um parâmetro chamado item do tipo ItemLista, este parâmetro
receberá a referência de um item da lista e irá adicioná-la na vari-
ável listaItens, chamando o método add, deste objeto como
visto na linha 8.

9-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Ainda na classe ListaDeCompras definimos o método re-
moverTodosItens, veja que este método não recebe nenhum pa-
râmetro, e tem como objetivo, remover todos os itens da lista por
meio de uma chamada ao método clear, como visto na linha 12.
Agora que temos o modelo de dados escrito, vamos começar a
implementação do layout da MainActivity, que será responsável
por exibir a lista de itens que deverão ser considerados na compra.

9.5 Definindo o layout da MainActivity


O layout da MainActivity será o primeiro conjunto de ele-
mentos gráficos que o usuário verá quando inicializar o aplicativo.

Figura 9-4: layout da MainActivity.

9-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Neste layout, teremos dois botões do tipo FloatingAc-
tionButton, um deles será usado para chamar a Activity que
vai inserir um item na lista e o outro será utilizado para apagar
todos os itens da lista.
Teremos também neste layout um elemento do tipo Recy-
clerView, este elemento será o responsável por exibir a lista com
os itens que forem adicionados pelo usuário.
Agora na pasta res no navegador de projeto, ou seja, no lado
esquerdo da tela do Android Studio, abra a pasta app, e depois
abra a pasta res.
Dentro da pasta res existe uma outra pasta chamada layout,
abra esta pasta e selecione o arquivo activity_main.xml.
Na paleta de componentes selecione o grupo chamado Com-
mon, e no lado direito da paleta escolha o componente chamado
RecyclerView, arraste esse componente para a tela de design e
adicione as restrições de layout, como mostrado na figura abaixo:

9-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Figura 9-5: Restrições de layout do RecyclerView.

Como será necessário acessar este elemento pelo código da


classe MainActivity, precisamos modificar sua propriedade id
para listaDeComprasRecyclerView.
Agora que temos o elemento RecyclerView posicionado
corretamente vamos adicionar o botão que vai chamar a Activi-
ty de adicionar itens, para isso, selecione na paleta de elementos
o grupo chamado Buttons, agora no lado direito escolha o ele-
mento FloatingActionButton, e arraste para a tela de layout,
posicione este elemento no canto inferior direito, e modifique a sua
imagem para @android:drawable/ic_input_add, alterando
o atributo srcCompat.
Adicione duas restrições de layout uma para o lado direito
do elemento pai chamada de EndOf parent e outra para a parte

9-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


inferior do elemento pai chamada de BottomOf parent, de o
valor de 16 para ambas as restrições. Agora modifique o id, deste
elemento para adicionaItemFloatButton.
De maneira semelhante adicione outro elemento do tipo
FloatingActionButton, pare este elemento escolha a ima-
gem @android:drawable/ic_menu_delete, para a proprie-
dade srcCompat.
Modifique a propriedade id, deste elemento para remover-
TodosFloatButton, e não se esqueça de adicionar duas restri-
ções de layout, uma delas será para o lado esquerdo do elemento
pai chamada de StartOf parent e outra para a parte inferior do
elemento pai chamada de BottomOf parent, ambas de valor 16.
Por fim, escolha uma cor com tom de vermelho para alterar a
cor do botão modificando a propriedade backgroundTint. Pron-
to, temos agora o layout completo da MainActivity.

9.6 Definindo o layout da célula da lista de itens


O próximo passo que vamos executar é a criação do layout
que cada linha da lista que será exibida pelo elemento Recycler-
View terá.
Queremos mostrar em cada uma das linhas, a quantidade, o
nome e um indicador que diz se o item foi comprado ou não, veja
a imagem abaixo para ter uma ideia de como vai ficar este layout:

9-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Figura 9-6: Layout das linhas da tabela.

A primeira coisa que vamos fazer é criar um novo arquivo


chamado linha_lista_compra.xml, crie este arquivo na pasta
layout, dentro da pasta res, clicando com o botão direito do mou-
se e escolhendo a opção new, Layout Resource File.
Depois que o arquivo for criado, apague o elemento raiz e
adicione um elemento do tipo LinearLayout, este elemento
pode ser encontrado na paleta de elementos no grupo Layouts, e
no lado direito escolha a opção LinearLayout (horizontal),
arraste este componente para a parte de layout do Android Studio
e modifique a propriedade padding para o valor 8dp de maneira
dar uma margem de 8dp para todos os cantos do elemento.
Mude também os atributos layout_width para match_
parent, isso fará com que a largura do elemento fique igual a lar-
gura do pai.

9-14
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Altere também a propriedade layout_height para wrap_
content, isso faz com que a altura do componente seja o suficien-
te para mostrar os elementos filhos.
Agora chegou a vez de adicionarmos o componente do tipo
CardView, este componente é muito utilizado no Android, pois
por meio dele podemos organizar os dados em containers, es-
tes containers possuem propriedades como arredondamento de
bordas sombras entre outras.
O elemento CardView é muito utilizado também na exi-
bição de dados em listas, como é o caso do aplicativo que esta-
mos escrevendo.
Para adicionar o elemento CardView escolha na paleta
de componentes o grupo Containers e no lado direito a opção
CardView, arraste este componente para o editor de layout do
Android Studio, de maneira que ele apareça como filho do compo-
nente LinearLayout que foi adicionado anteriormente.
Modifique a propriedade layout_height para 64dp, isso
fará com que o tamanho da linha fique fixo em 64dp. Modifique
também a propriedade layout_width para match_parent,
pois queremos que o CardView ocupe todo o espaço horizontal
do elemento pai.
Queremos arredondar os cantos do card, por isso vamos
modificar a propriedade cardCornerRadius para 16dp, por
fim mudamos a cor da propriedade cardBackgroundColor
para @color/teal_700, mas você pode escolher a cor que mais
lhe agradar.
Chegou a hora de colocarmos um elemento Cons-
traintLayout dentro do CardView, faremos isso para po-
dermos organizar os outros elementos utilizados às restrições de

9-15
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


layout, para isso escolha o grupo Layouts na paleta de componen-
tes e no lado direito, arraste o componente ConstraintLayout
para o editor.
Modifique as opções layout_width para match_parent,
e layout_height para 64dp.
Com o elemento ConstraintLayout adicionado, podemos
começar a colocar os elementos que vão exibir as informações, co-
meçaremos então pelo TextView que vai exibir a quantidade dos
itens, vamos modificar a propriedade id deste elemento para qt-
dTextView e a propriedade textSize para 20sp.
Modifique as restrições de layout deste componente confor-
me mostrado na figura abaixo:

Figura 9-7: Restrições de layout da quantidade.

9-16
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Chegou a vez do componente do tipo TextView que vai ser
usado para mostrar o nome do item na linha da tabela, vamos mo-
dificar o id deste componente para itemTextView e o atributo
textSize para 20sp. Veja na figura abaixo como vão ficar as res-
trições de layout.

Figura 9-8: Restrições de layout do nome do item.

Para terminar o layout da linha, vamos adicionar o último


componente que será do tipo ImageView, este componente é uti-
lizado quando queremos inserir imagens no layout, vamos modi-
ficar o id deste componente para marcaCompradoImageView,
pois teremos que acessa-lo pela MainActivity.
Iremos usar este componente para mostrar uma imagem que
vai representar se o item já foi comprado ou não, ou seja quando

9-17
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


o usuário clicar na linha da tabela que representa este item uma
nova Activity será lançada, e nesta Activity existirá um botão
com o título comprado, quando o usuário clicar neste botão deve-
remos mostrar na lista uma outra imagem que indicará que este
item já foi comprado.
Inicialmente, vamos definir a imagem desta ImageView
modificando a propriedade srcCompa para o valor @android:-
drawable/star_big_off. Fique à vontade para selecionar outras
imagens, aproveite para dar uma olhada em todos os ícones que o
Android oferece acessando a biblioteca @android:drawable.
Para terminarmos com o layout da linha que vai representar
o item na tabela, vamos acertar as restrições, abaixo, basta seguir o
que está feito na imagem abaixo:

Figura 9-9: Restrições de layout da imagem de item marcado

9-18
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Agora temos o formato da linha para exibirmos na tela, mas
veja que não basta apenas fazermos um laço de repetição e criarmos
quantas imagens destas forem necessárias, imagine se fizéssemos
isso, e por um acaso a lista contivesse mais de 10000 itens, prova-
velmente o aplicativo consumiria toda a memória do dispositivo.
Imagine se existisse um componente que fosse capaz de re-
ciclar as linhas, e só construísse as que fossem necessárias, ou seja
aquelas que são mostradas na tela, ai sempre teríamos um número
previsto de elementos, é para isso que serve o RecyclerView que
incluímos como elemento no layout da MainActivity.

9.7 Criando o ViewHolder para a RecyclerView


Antes de criarmos o adaptador, precisamos criar a classe que
vai representar a linha da lista de itens. Para que esta classe possa
ser usada no RecyclerView, deveremos fazer com que ela herde
suas propriedades da classe ViewHolder.
Crie um uma nova classe Kotlin no pacote adaptador, cha-
mada de LinhaLista, e entre com o código abaixo, para econo-
mizar espaço, omitimos as linhas com as declarações de import,
mas a numeração das linhas foi mantida. Para melhorar a leitura,
vamos inicialmente colocar a definição da classe com alguns mé-
todos e no decorrer do texto vamos adicionando e descrevendo os
outros métodos:

13| class LinhaLista(view: View) : Recycler-


View.ViewHolder(view) {
14|   var linhaListaView = view
15|

9-19
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


16|   init {
17|   linhaListaView.setOnClickListener {
18|    visualizaItem()
19|   }
20|  }
21|
22|   private fun visualizaItem() {
23|    val itemIndice = this.adapterPosition
24|   
val visualizaItemIntent = Intent(li-
nhaListaView.context,
25|   VisualizaItemActivity::class.java)
26|
27|   
visualizaItemIntent.putExtra
(“itemIndice”,itemIndice)
28|   
C ontextCompat.startActivity(linha-
ListaView.context,
29|   visualizaItemIntent,
30|   null)
31|  }
32|  :
33|  :
34| }

Começamos então na linha 13 com a palavra chave class, e


na sequência escrevemos o nome que vai definir esta classe ou seja
o nome LinhaLista.

9-20
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Veja que entre o construtor desta classe recebe um parâme-
tro do tipo view, e que a nova classe LinhaLista, tem como clas-
se mãe a classe RecyclerView.ViewHolder.
Logo na sequência na linha 14, armazenamos o parâmetro
recebido na variável imutável chamada linhaListaView, utili-
zaremos esta referência mais à frente na hora que formos acessar
os elementos da linha para exibir as informações.
Já na linha 16 definimos o construtor da classe, dentro das
chaves fazemos uma chamada para o método setOnClickLis-
tener do objeto linhaListaView, e passamos como parâmetro
uma chamada para o método visualizaItem, que está definido
logo abaixo.
O método visualizaItem, que está definido na linha 22,
tem como objetivo carregar na tela a Activity que vai dar ao usu-
ário a opção de marcar o item como comprado.
Na primeira linha do método, ou seja, na linha 23, salva-
mos a posição do item na lista em uma variável imutável chama-
da itemIndice, isto é necessário pois precisaremos passar esse
índice para a Activity que vamos lançar, pois com esse índice
a VisualizaItemActivity, será capaz de identificar na classe
de modelo chamada ListaDeCompras qual a posição correta do
elemento na variável listaItens.
Para conseguirmos disparar uma nova Activity, precisa-
mos criar um objeto do tipo Intent, se traduzirmos para o portu-
guês, podemos pensar no objeto intent como sendo uma inten-
ção, então você pode lembrar que o Intent é uma intenção para
lançar uma Activity.
Então na linha 24 chamamos o construtor do objeto Intent,
passando o primeiro parâmetro como sendo o context da view

9-21
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


que vai criar o Intent, podemos entender o tipo Context como
sendo uma abstração para os recursos da aplicação.
Na sequência, passamos o parâmetro VisualizaIte-
mActivity::class.java, essa expressão indica que estamos
usando reflexão do java para extrairmos o tipo da classe java ao
qual pode ser traduzida a classe Kotlin chamada VisualizaIte-
mActivity. Por fim armazenamos na variável imutável chama-
da visualizaitemItent a referência para esse novo Intent
que criamos.
Uma maneira de mandarmos informações de uma Activi-
ty para outra é por meio de uma estrutura de chave valor que as
instâncias do tipo Intent fornecem. Lembre-se que precisamos
enviar para a VisualizaItemActivity, qual o índice do ele-
mento ao qual a linha recebeu o click do usuário.
Para isso acontecer, na linha 27, chamamos o método pu-
tExtra, do objeto visualizaitemIntent, utilizaremos como
chave para esta informação a String denominada pelo texto
ItemIndice e o segundo parâmetro é o valor que será armaze-
nado para esta chave, ou seja será o valor do índice da lista que o
item pertence.
Com o Intent preparado, podemos carregar a nova Acti-
vity, faremos isso chamando o método estático startActivity
da classe ContextCompat, podemos entender a classe Contex-
tCompat, como sendo uma classe ajudante que dá acesso a alguns
método definidos no contexto da aplicação.
Novamente passamos como primeiro parâmetro para o mé-
todo startActivity o atributo context da variável imutável
linhaListaView, como segundo parâmetro passamos a variável
visualizaItemIntent, e por fim passamos o parâmetro op-
tions, como sendo null.

9-22
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Portanto, sempre que este método for chamado, ele vai dis-
parar uma nova VisualizaItemActivity. Até esse ponto ainda
não definimos esta Activity, então não se preocupe, pois o seu
código não vai compilar devido a esse fator.
Dentro da classe LinhaLista, também temos um método
público chamado configuraLinhaLista, este método recebe
como parâmetro uma instância do modelo de dados, pega os va-
lores e preenche os elementos com os dados, fazendo com que as
linhas da lista mostrem de maneira correta os elementos do item
da compra. Logo abaixo está o código deste método:

33| fun configuraLinhaLista(itemLista: ItemLista) {


34|  
val itemTextView = linhaListaView.find-
ViewById<TextView>(R.id.itemTextView)
35|  
val qtdTextView = linhaListaView.find-
ViewById<TextView>(R.id.qtdTextView)
36|  
val marcaCompradoImageView = linha-
ListaView.findViewById<ImageView>(R.
id.marcaCompradoImageView)
37|   itemTextView.text = itemLista.nome
38|   qtdTextView.text = itemLista.qtd.toString()
39|   if (itemLista.comprado) {
40|   
marcaCompradoImageView.setImageResour-
ce(android.R.drawable.btn_star_big_on)
41|   } else {
42|   
marcaCompradoImageView.setImageResour-
ce(android.R.drawable.btn_star_big_off)
43|  }
44| }

9-23
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Na linha 34, pegamos uma referência do elemento do tipo
TextView que vai mostrar na linha da tabela o nome do item que
deve ser comprado, e armazenamos esta referência na variável
imutável chamada itemTextView, veja que fizemos uso do méto-
do findViewById, chamando este método da referência do objeto
linhaListaView, que é uma referência para a linha da lista que
vai ser exibida.
Na próxima linha fazemos o mesmo para o TextView que
possui o id qtdTextview, este elemento do tipo TextView será
utilizado para exibirmos a quantidade que deverá ser comprada
deste item. Armazenaremos esta referência na variável imutável
chamada qtdTextview.
Por fim, precisamos de uma referência para o elemento do
tipo ImageView que será utilizado para marcar se o elemento já
foi comprado ou não. Essa referência será armazenada na variável
imutável marcaCompradoImageView.
Agora que temos as referências para os objetos do tipo Tex-
tView armazenadas em itemTextView e qtdTextView, pode-
mos passar os valores do modelo para a propriedade text destes
objetos, fazemos isso na linha 37 para o nome do item e na linha
38 para a quantidade do item, atente ao detalhe que precisamos
converter a quantidade para o tipo String, pois o atributo texto
do elemento TextView é do tipo String e não vai aceitar um ele-
mento do tipo Int.
No caso do elemento que mostra a imagem, precisamos fa-
zer uma lógica simples, precisamos verificar se o valor do atributo
comprado da instância do objeto é true, isso quer dizer que va-
mos mostrar a imagem referenciada pela constante android.R.
drawable.btn_star_big_on, ou seja estaremos indicando ao
usuário que este item já foi comprado.

9-24
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Caso contrário, se o atributo comprado, possuir o valor fal-
se então deveremos modificar a imagem para a que está armaze-
nada na referência android.R.drawable.btn_star_big_off
Em ambos os casos, fizemos uso do método setImageRe-
source, da instância da classe ImageView referenciada pela vari-
ável imutável marcaCompradoImageView.

9.8 Integrando o Adapter da RecyclerView com a


MainActivity
Para que seja possível pegarmos os dados do modelo e pas-
sarmos estes dados para o componente RecyclerView precisa-
mos de um adaptador traduzindo para o inglês adapter.
É exatamente isso que vamos escrever agora, mas antes pre-
cisamos criar uma classe nova no pacote adaptador, chamare-
mos esse arquivo de ListaDeComprasAdapter. O Código desta
classe está escrito logo abaixo, as linhas de importação foram omi-
tidas para melhorar a legibilidade:

9| class ListaDeComprasAdapter(val itens:


List<ItemLista>): RecyclerView.Adap-
ter<LinhaLista>() {
10|
11|  override fun onCreateViewHolder(parent:
ViewGroup, viewType: Int):LinhaLista {
12|   
return LinhaLista(LayoutInflater.
from(parent.context).inflate(R.layout.
linha_lista_compra, parent, false))
13|  }

9-25
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


14|
15|  
override fun onBindViewHolder(holder:
LinhaLista, position: Int) {
16|    val itemLista = itens[position]
17|    holder.configuraLinhaLista(itemLista)
18|  }
19|
20|   override fun getItemCount(): Int {
21|   return itens.count()
22|  }
23| }

Inicialmente definimos o nome dessa classe como sendo


ListaDeComprasAdapter, que tem como pai a classe Recy-
clerView.Adapter.
O construtor dessa classe vai receber como parâmetro um
tipo List dos objetos ItemLista, ou seja, uma lista com os itens
que vão sendo adicionados pelo usuário, como dito anteriormen-
te esta classe vai conectar os itens desta lista com instâncias da
classe LinhaLista.
Para que a RecyclerView possa exibir a lista com os itens,
seu adapter, que é a classe que estamos escrevendo agora, deve-
rá realizar três tarefas, uma delas é criar as instâncias das view
holders, ou seja, criar as instâncias da classe que vai representar
cada uma das linhas.
Esta tarefa é feita pelo método onCreateViewHolder na
linha 11, este método recebe como primeiro parâmetro um objeto
do tipo ViewGroup chamado parent.

9-26
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


No Android, objetos do tipo ViewGroup são usados como
containers para outros objetos do tipo View, que é o caso da
nossa classe LinhaLista que representa uma linha da tabela. O
segundo parâmetro chamado viewType é do tipo Int e informa
qual é o tipo do parent que está sendo recebido, neste exemplo
não faremos uso deste elemento.
O método onCreateViewHolder, deverá retornar um ele-
mento do tipo LinhaLista, ou seja, deveremos pegar o layout que
definimos no arquivo linha_lista_compra.xml e construir
uma instância do objeto LinhaLista, partindo deste arquivo.
Isto foi feito na linha 12, quando definimos a classe Linha-
Lista, criamos um construtor para ela que recebe um objeto do
tipo View.
A classe LayoutInflater possui dois métodos para alcan-
çarmos este objetivo, o primeiro é o método from, que recebe
como parâmetro o contexto da View que será o pai da nova View
que será criada.
E o método inflate, que recebe como primeiro parâmetro
a constante que representa o arquivo xml onde o layout da View
foi feito, no nosso caso este layout é referenciado pela constante
R.layout.linha_lista_compra.
O segundo parâmetro do método inflate é novamente a
View que vai conter a nova View que está sendo criada, que neste
caso está sendo referenciado pelo parâmetro parent. Não entra-
rei em detalhes sobre o último parâmetro, apenas vamos passar o
valor false.
Pronto, basta agora usar a palavra chave return para fazer
com que o método retorne a View que acabou de ser criada direta-
mente do arquivo xml.

9-27
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


A próxima tarefa que o adaptador deverá fazer é pegar os da-
dos de cada posição do parâmetro itens, onde cada elemento da
lista é uma instância do objeto ItemLista e contém as informa-
ções nome, quantidade e se o item já foi comprado.
Esta tarefa é implementada na linha 15 até 18 pelo método
onBindViewHolder, onde o primeiro parâmetro chamado de
holder, é do tipo LinhaLista, ou seja, a classe onde implemen-
tamos o método configuraLinhaLista, responsável por rece-
ber um parâmetro do tipo ItemLista e popular os elementos do
layout com as informações do modelo.
O segundo parâmetro é chamado de position, e é do tipo
Int, este parâmetro representa o índice do elemento que vai ser
exibido na lista, começando do valor 0 até o número de elemen-
tos menos 1.
Dito isso, na linha 16 usamos o parâmetro position como
índice da lista itens e armazenamos este valor na variável imutável
itemLista. Que será usada como parâmetro na próxima linha na
chamada do método configuraLinhaLista, veja que este méto-
do foi chamado do parâmetro holder que é do tipo LinhaLista.
Por fim, o adapter deverá retornar o número de elementos
que deverão ser exibidos na lista. O responsável por essa última
tarefa é o método getItemCount, que não recebe nenhum parâ-
metro e deverá retornar um inteiro, que vai representar quantos
itens deverão ser exibidos na lista. Este método foi escrito na linha
20, e na linha 21.
Como vamos exibir todos os elementos da lista armazenada
no parâmetro itens, devemos apenas retornar o número de itens
desta lista, por isso na linha 21 apenas chamamos o método count
deste objeto.

9-28
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


Com o Adapter definido, falta apenas conectarmos os dados
do modelo para isso criamos o método atualizaListaDeCom-
pra, como mostrado abaixo:

1| private fun atualizaListaDeCompra() {


2|   layoutManager = LinearLayoutManager(this)
3|  
listaDeComprasAdapter = ListaDeCompra-
sAdapter(ListaDeCompras.listaItens)
4|  listaDecomprasRecycleView.layoutMana-
ger = layoutManager
5|   l i s t a D e c o m p r a s R e c y c l e V i e w . a d a p -
ter = listaDeComprasAdapter
6| }

Inicialmente na linha 2, definimos tipo de layout que a


RecycleView vai assumir, para simplificar vamos usar o Li-
nearLayout, que dispõe os elementos filhos verticalmente por
padrão, vamos armazenar uma referência para este objeto na vari-
ável layoutManager.
Na linha 3 criamos uma instância da classe ListaDeCom-
prasAdapter, veja que passamos a lista de itens como parâmetro
para este construtor, isso fará com que o adapter tenha acesso
ao modelo.
Agora basta definirmos o layout manager da RecyclerView,
fazemos isso atribuindo a variável de referência layoutManger
ao atributo layoutManager da referência para a RecycleView
armazenada na variável listaDeComprasRecycleView.

9-29
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 9

R EC Y C LER V IEW E R EC YCLER AD A PTER


E por fim definimos o atributo adapter da variável lista-
DeComprasRecycleView, a variável listaDeComprasAdap-
ter que já possui uma referência para o modelo.
Como a ideia do aplicativo será chamar uma nova Activi-
ty toda a vez que formas incluir um novo item na lista, devemos
atualizar a listaDeComprasRecycleView, sempre que a Mai-
nActivity voltar a ser vista pelo usuário, para isso devemos so-
brescrever o método onResume, como feito abaixo:

1| override fun onResume() {


2|  super.onResume()
3|  atualizaListaDeCompra()
4| }

Seguindo as boas práticas chamamos o método onResume


usando como referência a classe mãe, por isso utilizamos a palavra
chave super na linha 2.
Em seguida na linha 3 chamamos o método atualizaLis-
taDeCompra. Como o usuário vai ter inserido um novo item, ao
chamarmos este método, estaremos garantindo que o modelo vai
ser atualizado no dentro do Adapter e o item novo será mostrado
na lista.
Até aqui escrevemos todo o código necessário para exibir a
lista com todos os itens que foram cadastrados pelo usuário, como
visto anteriormente, esta lista vai ser exibida assim que o usuário
entrar na aplicação.
No próximo capítulo veremos como incluir um novo item e
também como marcar um item como já comprado.

9-30
 EXERCÍCIOS PROPOSTOS

1) Qual é o significado da sigla Arquitetura MVC?

(  ) -a) Modern Vector Controller.


(  ) -b) Mais Visualização Controller.
(  ) -c) Modelo Visualização Controlador.
(  ) -d) Mínimo Visualizador Comum.
(  ) -e) Máximo Visualizador Comum.

2) Qual é a classe do aplicativo lista de compras que representa o modelo


de dados?

(  ) -a) É a classe LinhaLista.


(  ) -b) É a classe MainActivity.
(  ) -c) É a classe ItemLista.
(  ) -d) O projeto lista de compras não possui um modelo de dados.
(  ) -e) É a classe VisualizaItemActivity.

3) Sobre a classe ListaDeCompras, escolha a alternativa correta:

(  ) -a) O Aplicativo lista de compras, possui várias instâncias da


classe ListaDeCompras.
(  ) -b) A classe ListaDeCompras é responsável por persistir os da-
dos dos itens da lista e sempre que entramos no aplicativo
vemos os dados que foram inseridos anteriormente.
(  ) -c) Na linha 5 existe um erro, pois a variável listaItens deveria
ser declarada como sendo imutável.
(  ) -d) A classe ListaDeCompra é um singleton, ou seja, temos ape-
nas uma instância desta classe na aplicação, esta classe man-
tém uma lista de itens em memória e quando o aplicativo é
encerrado esta lista é perdida.
(  ) -e) Esta classe faz parte da camada de visualização da aplicação.

9-31
4) Escolha a alternativa correta sobre a classe LinhaLista:

EX ER C ÍC IO S PR O PO STO S
(  ) -a) A classe LinhaLista faz parte do modelo do aplicativo lista
de compras.
(  ) -b) A classe LinhaLista é do tipo RecycleView.ViewHolder, ou
seja, ela representa o código de cada uma das linhas que se-
rão exibidas pela RecycleView.
(  ) -c) A classe LinhaLista é o adapter da classe RecyclerView que
vai exibir as linhas dos itens da lista de compras.
(  ) -d) Não podemos acessar o modelo diretamente pela classe
LinhaLista.
(  ) -e) N.d.a

5) Escolha a alternativa correta sobre a classe ListaDeComprasAdapter:

(  ) -a) Precisamos sobrescrever os métodos onCreateViewHolder,


que gerencia a criação das views de cada linha da lista, o
método onBindViewHolder, que pega os dados do modelo e
carrega na view e por fim o método getItemCount, que for-
nece a quantidade dos itens que serão exibidos na lista.
(  ) -b) Podemos retornar um valor literal no método getItemCount.
(  ) -c) Não é necessário sobrecarregar o método getItemCount.
(  ) -d) A classe ListaDeComprasAdapter é do tipo Activity.
(  ) -e) O método onBindViewHolder não recebe a posição da lista
ao qual o viewholder deve ser populado

6) Sobre a classe ItemLista, escolha a alternativa correta:

1| data class ItemLista(val qtd: Int,


2| val nome: String,
3| var comprado: Boolean) {
4|
5| }

9-32
(  ) -a) A classe foi declarada de maneira errada pois os dados dos
parâmetros deveriam ter sido armazenados nos atributos de

EX ER C ÍC IO S PR O PO STO S
mesmo nome.
(  ) -b) O parâmetro comprado, deveria ter sido marcado com a pa-
lavra chave val.
(  ) -c) Na linha 3 o parâmetro comprado foi corretamente marcado
com a palavra chave var pois este parâmetro será modificado
e deverá ser mutável.
(  ) -d) A palavra chave data não está definida na linguagem Kotlin.
(  ) -e) N.d.a.

7) Considere o código abaixo e escolha a alternativa correta:

1| private fun atualizaListaDeCompra() {


2|   layoutManager = LinearLayoutManager(this)
3|   listaDeComprasAdapter = ListaDeCompra-
sAdapter(ListaDeCompras.listaItens)
4|  listaDecomprasRecycleView.layoutMana-
ger = layoutManager
5|   l i s t a D e c o m p r a s R e c y c l e V i e w . a d a p -
ter = listaDeComprasAdapter
6| }

(  ) -a) O método acima não é necessário pois o adapter é associado


automaticamente ao recyclerview
(  ) -b) Este método cria um layout manager, cria o adapter e asso-
cia os dois elementos a referência listaDeComprasRecycle-
View, com isso os dados do modelo serão exibidos na tela
em forma de lista.
(  ) -c) Este método deveria fazer parte do pacote Modelo
(  ) -d) Não podemos acessar diretamente o atributo listaItens da
classe ListaDeCompras, pois esta classe não foi definida
como um singleton e precisamos de uma instância.
(  ) -e) Podemos remover a linha 2 e a linha 4 pois não é obrigatório
definirmos um layout para a recyclerview.

9-33
8) Sobre o método onResume escolha a alternativa correta:

EX ER C ÍC IO S PR O PO STO S
1| override fun onResume() {
2|  super.onResume()
3|  atualizaListaDeCompra()
4| }

(  ) -a) Sobrescrevemos o método onResume para garantir que


quando o usuário cadastre um novo item, este item seja exi-
bido na tela.
(  ) -b) Este código vai gerar um erro pois o método onResume não
existe na classe mãe da MainActivity.
(  ) -c) Não podemos chamar o método atualizaListaDeCompra,
pois ele foi marcado como private.
(  ) -d) Ao invés de utilizarmos o método onResume, poderíamos
ter utilizado o método onCreate
(  ) -e) N.d.a

9) Qual é a classe da plataforma Android que consideramos com sendo par-


te da camada de controle da arquitetura MVC:

(  ) -a) LinearLayoutManager
(  ) -b) RecyclerView
(  ) -c) FloatingActionButton
(  ) -d) TextView
(  ) -e) AppCompatActivity

10) Qual palavra chave da linguagem Kotlin se refere a um modificador que


indica que a classe é um modelo de dados:

(  ) -a) Data
(  ) -b) Open
(  ) -c) Private
(  ) -d) Model
(  ) -e) Public

9-34
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 10:
VISUALIZANDO E ADICIONANDO ITENS
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
10.1 Introdução
Neste capítulo vamos criar a Activity que possibilitará ao
usuário incluir novos itens em sua lista de compras, está Acti-
vity será lançada assim que o usuário clicar no botão com ícone
da imagem do símbolo positivo que está no canto inferior direito
da MainActivity.
Mostraremos também neste capítulo como vai ser escrita
a Activity que o usuário vai utilizar para marcar o item como
comprado, esta Activity será lançada quando o usuário clicar na
linha da tabela.

10.2 Criando o layout da inclusão de itens


Inicialmente vamos criar o novo layout para a tela de inclu-
são de itens, precisaremos fornecer ao usuário um campo onde ele
vai entrar com o nome do item que vai ser incluído na lista de com-
pras, e um outro campo onde o usuário vai entrar com a quantida-
de do item que deve ser comprado, veja na figura abaixo, como vai
ficar este layout:

10-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Figura 10-1: Layout da Activity para a inclusão de novos itens

Para este layout vamos criar um arquivo chamado acti-


vity_adiciona_item.xml. Inicialmente vamos adicionar um
elemento do tipo TextView, daremos ao atributo text desse ele-
mento o texto Nome, pois ele vai indicar que o campo abaixo deverá
ser usado pelo usuário para que ele forneça o nome do item que
deverá ser comprado.
Para melhorar a legibilidade coloque o valor 20sp no atri-
buto textSize, como não precisaremos de uma referência no
código para este campo, não precisamos modificar a propriedade

10-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
id. Adicione uma restrição de layout de valor 16 ao topo da view
pai, e uma restrição de valor 16 da borda esquerda da view pai.
Temos agora que adicionar o elemento do tipo EditText,
este elemento vai ser responsável por receber o texto referente ao
nome do item que vai ser inserido na lista de compra.
Como teremos que acessar o conteúdo que o usuário digitou,
para guardar no modelo e posteriormente mostrar na lista, vamos
modificar o id deste elemento para itemNomeEditText.
Para que o campo ocupe todo o espaço horizontal menos o
espaço ocupado pelas restrições de layout, modifique o atributo
layout_width para 0dp.
Modifique também o atributo minHeight para 48dp, por
fim coloque uma restrição de valor 16 com relação ao lado esquer-
do da view pai, outra de tamanho 16 com relação ao lado es-
querdo da view pai e por fim uma restrição de tamanho 8 com
relação ao TextView que criamos no passo anterior.
Temos agora que incluir um elemento do tipo TextView que
vai mostrar ao usuário o texto Quantidade, para isso modifique o
atributo text, para este valor.
Não precisamos alterar o atributo id deste elemento pois
não será necessário acessar nenhuma propriedade dele através da
Activity. Modifique o atributo textSize, deste elemento para
20sp, e adicione uma restrição de layout de valor 32, que tenha
relação com o campo texto do passo anterior e mais uma restrição
de layout com relação ao lado esquerdo da view pai, que pos-
sua valor 16.
Precisamos agora de um campo onde o usuário vai inserir
a quantidade do item que deverá ser comprado, para isso insira
no layout um elemento do tipo EditText, mude a propriedade

10-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
inputType para number, pois só receberemos valores numéri-
cos inteiros.
Para este campo deveremos modificar o atributo id, pois
iremos pegar o valor que o usuário digitou e armazenar no mode-
lo. Vamos então inserir neste campo o valor itemQtdEditText.
Modifique também o atributo minHeight para 48dp assim vamos
garantir que o campo sempre possua um tamanho mínimo razoá-
vel para que o usuário consiga entrar com o valor.
Por fim, crie uma restrição de layout de valor 8 que aponte
para o elemento que representa o texto Quantidade, e outra restri-
ção de layout apontando para o lado esquerdo da view que con-
tém este elemento, com valor de 16.
O último elemento que vamos inserir neste layout vai ser do
tipo Button, arraste um novo elemento deste tipo para o editor de
layout e modifique seu atributo text para o texto salvar.
Precisamos pegar o evento de clique neste botão, portanto
precisaremos de uma referência para este elemento na Activity
que vai exibir esse layout, para isso modifique o atributo id, para
o texto salvarButton.
Crie uma restrição de layout de tamanho 16 com o lado es-
querdo da view que contém este objeto, e outra restrição de layout
de tamanho 32 relacionando campo onde o usuário vai entrar com
o valor da quantidade. Veja na figura abaixo como deverá ficar as
restrições de layout ao final do processo.

10-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Figura 10-2: Restrições de layout.

10.3 Criando a Activity para inclusão de itens


Com o layout já definido, vamos criar uma nova classe do
tipo AppCompatActivity, para isso clique com o botão direi-
to do mouse no pacote chamado controlador e escolha a opção
Kotlin Class/File. De o nome de AdicionaItemActivity.
Poderíamos ter criado esta Activity de outra maneira,
apenas escolhendo a opção New, depois clicando em Activity e
por fim em Empty Activity, desta maneira teríamos tudo já
configurado, mas vamos aproveitar esta oportunidade e criar a
Activity manualmente.

10-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Toda a Activity do aplicativo Android deverá estar re-
gistrada no arquivo chamado AndroidManifest.xml, que fica
dentro da pasta manifests. Todo projeto de aplicativo Android
precisa ter um arquivo AndroidManifest, é nele onde estão rela-
cionadas informações específicas do aplicativo que são necessárias
tanto em tempo de compilação quanto em tempo de execução.
Essas informações vão do nome do ícone, até permissões
para o uso da câmera e da localização. As Activitys também de-
vem estar descritas neste arquivo, inclusive a MainActivity que
recebe um parâmetro especial que vai indicar ao Android que é
essa tela que deverá aparecer quando o usuário abrir a aplicação.
Para melhorar a leitura, vamos mostrar abaixo apenas as linhas do
arquivo AndroidManifest que são necessárias para registrar a
nova Activity que estamos criando.

1| <?xml version=”1.0” encoding=”utf-8”?>


2| <manifest xmlns:android=”http://schemas.
android.com/apk/res/android”
3|  package=”com.segundo.listadecompras”>
4|
5|  <application>
6|  :
7|  :
15|  <activity
16|   
android:name=”.controla-
dor.AdicionaItemActivity”
17|   android:exported=”true” />

10-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
18|  :
19|  :
27|  </application>
28|
29| </manifest>

O importante aqui são as linhas 15 até 17, como o arquivo


AndroidManifest é do tipo xml, utilizaremos a notação de tags
<>, para marcar a declaração de uma Activity, utilizamos a
tag <activity>.
Para indicarmos qual Activity que será declarada deve-
mos usar o atributo android:name, e o valor “.controlador.
AdicionaItemActivity”, veja que o texto que será atribuído
faz referência ao pacote onde a classe está e ao nome do classe que
iremos escrever.
Com a nova Activity declarada no arquivo AndroidMa-
nifest.xml, vamos começar a escrever a classe AdicionaIte-
mActivity, veja abaixo como vai ficar este código, novamente
omitimos as declarações de importação, para melhorar a legibili-
dade e também mostraremos inicialmente apenas a declaração da
classe seguida do método onCreate, na sequência descreveremos
os outros métodos.

11| class AdicionaItemActivity: AppCompatActivity() {


12|
13|  
override fun onCreate(savedInstanceS-
tate: Bundle?) {
14|   super.onCreate(savedInstanceState)

10-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
15|   
setContentView(R.layout.
activity_adiciona_item)
16|    defineBotaoSalvar()
17|  }
18|
19|  :
20|  :
21|
22| }

Na linha 11 declaramos a classe AdicionaItemAc-


tivity, veja que usamos o símbolo dois pontos para indi-
car que esta classe herda todos os métodos e atributos da
classe AppCompatActivity.
Como dito anteriormente na MainActivity, precisamos
sobrescrever o método onCreate, que vai ser executado quando a
AdicionaItemActivity for lançada.
Sempre que sobrescrevemos um método devemos fazer uma
chamada para o método utilizando a referência da classe mãe que
pode ser acessada pela palavra chave super, e passando como pa-
râmetro o objeto savedInstanceState.
Na sequência utilizamos o método setContentView, pas-
sando como parâmetro a constante que possui a referência para o
layout desta tela que é a R.layout.activity_adiciona_item.
Ainda no método onCreate, na linha 16 precisamos fare-
mos uma chamada para o método defineBotaoSalvar, este mé-
todo está escrito logo abaixo:

10-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
19| private fun defineBotaoSalvar() {
20|  
val botaoSalvar = findViewById<But-
ton>(R.id.salvarButton)
21|   botaoSalvar.setOnClickListener {
22|    val item = criaItemLista()
ListaDeCompras.adicionarItemNaLista(item)
23|   
24|    finish()
25|  }
26| }

Este novo método não vai receber nenhum parâmetro, por-


tanto na linha 19, logo depois de escrito o nome do método, apenas
abrimos e fechamos os parênteses.
Na linha 20, vamos pegar uma referência do botão que o
usuário vai usar para salvar o novo item, novamente faremos isso
utilizando o método findViewById, veja que passamos o tipo do
elemento que é Button entre os sinais de maior e menor e por fim,
passamos como parâmetro a constante R.id.salvarButton,
que faz referência a esse elemento
Já com a referência do botão armazenada na variável imutá-
vel botaoSalvar, vamos fazer uso do método setOnClickLis-
tener, para definir o código que iremos executar quando o usuá-
rio clicar no botão salvar.
O que queremos fazer é, quando o usuário clicar no botão
queremos criar um item com os dados que ele forneceu, que são
o nome e quantidade, em seguida adicionar este item na lista de
compras e por fim finalizar a AdicionaItemActivity.

10-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Na linha 22 vamos chamar o método criaItemLista, este
método ainda não foi definido, mas vai ser responsável por pegar
os dados dos campos, criar um novo objeto do tipo ItemLista
com estes dados e retornar este objeto, ou seja, a variável imutá-
vel item, já possuirá os dados que foram entrados pelo usuário.
Por isso na linha 23 apenas incluímos este novo objeto na lista de
compras chamando o método adicionaItemLista, fazendo isso
diretamente da referência da classe ListaDeCompras que mar-
camos com o modificador object, ou seja, estamos utilizando o
padrão Singleton para fazer essa chamada.
Feito isso, já temos o nosso novo item adicionado na lista de
compras e podemos terminar a AdicionaItemActivity, para
isso na linha 24 chamamos o método finish, lembre-se que este
método foi herdado da classe AppCompatActivity.
Para terminarmos a classe AdicionaItemActivity, só
precisamos escrever o método criaItemLista, veja abaixo
como ficou:

28| private fun criaItemLista(): ItemLista {


29|  
val itemNomeTextView = findViewById<E-
ditText>(R.id.itemNomeEditText)
30|  
val itemQtdTextView = findViewById<Edit-
Text>(R.id.itemQtdEditText)
31|  
val itemNome = itemNomeTextView.
text.toString()
32|  val itemQtd = itemQtdTextView.text.toS-
tring().toInt()
33|   return ItemLista(itemQtd, itemNome, false)
34| }

10-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Como dito anteriormente o objetivo deste método é pegar os
dados dos campos e criar um objeto do tipo ItemLista, para isso
na linha 29 definimos a variável imutável itemNomeTextView,
utilizamos o método findViewById, passamos como parâmetro o
tipo do elemento que vamos procurar no layout que neste caso é o
EditText, e passamos como parâmetro a constante R.id.item-
NomeEditText, onde está armazenado o id que criamos para o
campo onde o usuário vai entrar o nome do item.
Na sequência fazemos o mesmo para o campo, onde o usu-
ário entrará com o valor da quantidade do item, utilizaremos no-
vamente o método findViewById, porém desta vez mudaremos
o parâmetro para a constante que faz referência o campo onde o
usuário vai entrar com a quantidade, por isso usamos a constante
R.id.itemQtdEditTExt.
A referência para este campo vai ficar armazenada na variá-
vel imutável chamada itemQtdTextView.
Chegou a hora de extrairmos os dados de cada uma das refe-
rências dos campos, na linha 31, começamos por pegar o nome do
item, para isso vamos utilizar a referência para o campo item nome
que está armazenada na variável imutável itemNomeTextView,
este dado está disponível no atributo text dessa variável.
Perceba que o tipo do atributo text não é String, por
isso precisaremos utilizar o método toString para fazer a con-
versão, armazenaremos este valor na variável imutável cha-
mada itemNome.
Faremos o mesmo com o valor da quantidade que foi en-
trada no campo da referência itemQtdTextView, novamente
teremos que primeiro converter o valor do atributo text, deste
campo para o tipo String, portanto novamente faremos uso do
método toString.

10-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Mas lembre-se que no modelo o atributo que representa a
quantidade é do tipo Int, ou seja, novamente teremos que fazer
uma nova conversão para este tipo, utilizando o método toInt.
Feito isto temos os dados extraídos dos campos e armazena-
dos nas variáveis imutáveis itemNome e itemQtd, agora preci-
samos criar o novo objeto do tipo ItemLista, para isso na linha
33 chamamos o construtor do objeto passando como primeiro pa-
râmetro a variável itemQtd, como segundo parâmetro a variável
itemNome e por fim vamos marcar este item que acabou de ser
incluído como não comprado ainda, ou seja, passaremos o valor
false para este último parâmetro. Com isso terminamos a imple-
mentação da AdicionaItemActivity.

10.4 Criando o layout para a visualização do item


Vamos agora para o último layout que falta para completar-
mos o aplicativo, este layout vai mostrar para o usuário o título
do item e um botão para que o usuário possa marcar o item como
comprado. A figura abaixo mostra como vai ficar este layout:

10-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Figura 10-3: Layout da visualização do Item

Novamente, como feito anteriormente, devemos inicialmen-


te criar um arquivo na pasta layout, que fica dentro da pasta res,
chamado de activity_visualiza_item.xml.
Feito isso, podemos começar a construir o layout para essa
Activity, iniciaremos por colocar um elemento do tipo Text-
View, utilizaremos este elemento para exibir o nome do item que
foi acessado.
Como vamos mudar a propriedade text deste elemen-
to em tempo de execução precisaremos ter uma referência deste

10-14
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
elemento no código, por isso vamos mudar o valor da propriedade
id para itemNomeTextView.
Modifique também o atributo textSize para o valor 32sp.
Vamos colocar uma restrição de layout que vai centralizar este ele-
mento horizontalmente e uma outra restrição que vai gerar uma
margem com valor de 96 do topo da view que contém este elemento.
Este layout precisará de mais um elemento do tipo Button,
novamente, como precisaremos definir o evento de clique neste
botão precisaremos de uma referência dele no código, para isso
vamos mudar o valor do atributo id para compradoButton.
Devemos também mudar o título deste botão para o texto
comprado. Por fim crie duas restrições de layout uma que fará um
distanciamento de 96 do elemento TextView criado anteriormen-
te e outra que vai centralizar este elemento do tipo Button hori-
zontalmente dentro da view container.

10.5 Criando a Activity para a visualização do item


Terminado o layout, vamos agora começar a escrever a clas-
se VisualizaItemActivity, para melhorar a legibilidade va-
mos remover as diretivas de importação e neste primeiro trecho
do código vamos mostrar apenas a declaração da classe e o mé-
todo onCreate.

10| class VisualizaItemActivity :


AppCompatActivity() {
11|   var itemIndice: Int? = 0
12|

10-15
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
13|  
override fun onCreate(savedInstanceS-
tate: Bundle?) {
14|   super.onCreate(savedInstanceState)
15|   
setContentView(R.layout.
activity_visualiza_item)
16|   
itemIndice = intent.extras?.getInt
(“itemIndice”,0)
17|   pegaNomeDoItem()
18|    defineBotaoComprado()
19|  }
20|  :
21|  :
22| }

Como a VisualizaItemActivity é uma Activity, pre-


cisamos marcar na sua definição que ela herda métodos e atributos
da classe AppCompatActivity, isso foi feito na linha 10.
Na sequência, na linha 11, definimos uma variável ite-
mIndice, usaremos esta variável para armazenar o índice do
elemento que foi selecionado na lista da MainActivity, este
valor será utilizado para acessarmos o elemento correto no atri-
buto listaItens.
Como esta classe é uma Activity, precisamos sobrescrever
o método onCreate, isto foi feito na linha 13. Da mesma forma
como foi feito anteriormente fazemos uma chamada para o método
da classe mãe usando a palavra chave super.
Na linha 15, utilizamos o método setContentView, para
instanciar os elementos do layout que são referenciados pela

10-16
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
constante R.layout.activity_visualiza_item. Passaremos
esta constante como parâmetro para o método setContentView.
Quando a VisualizaItemActivity é inicializada pela
MainActivity por meio da classe LinhaLista, temos na linha
27 desta classe a chamada para o método putExtra, recapitulan-
do, utilizamos este método para armazenar o valor da posição da
lista que foi clicado usando a chave itemIndice, logo na linha
16, da activity VisualizaItemActivity vamos acessar este
valor por meio do método getInt do atributo intent.extras
da Activity.
Vale a pena notar que utilizamos o símbolo ?, na chamada do
método getInt, isso significa que estamos fazendo uma chamada
segura ao método, esse termo é conhecido em inglês como sendo
uma safe call.
Isso acontece pois o valor do atributo extras, pode ser nulo,
e fazendo uso do operador ?, estamos dizendo ao compilador que
se o atributo extras for nulo então qualquer operação com este
atributo vai retornar nulo.
Antigamente, quando usávamos a linguagem java, o opera-
dor de chamada segura não existia e muitos erros do tipo Null-
PointerException, atormentavam a vida dos programadores,
como a linguagem Kotlin implementa o operador de chamada se-
gura, temos uma proteção para este tipo de situação.
Como estamos seguros de que a chave é a mesma que utili-
zamos quando chamamos o método putExtra, então neste caso
este valor nunca será nulo, porém como o compilador não pode
garantir isso, temos que usar o operador?.
Depois da linha 16 já temos definido o valor da variável ite-
mIndice, e ele poderá ser usado mais adiante. Após isso na linha

10-17
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
17 fizemos uma chamada ao método pegaNomeDoItem, que será
definido mais adiante, e terá como objetivo pegar o nome do item
do modelo e colocar esse valor no campo text do elemento Tex-
tView que criamos anteriormente no layout.
E na linha 18, chamamos o método defineBotaoComprado,
que vai fazer com que quando o usuário clique no botão comprado,
o item seja marcado como comprado.
Vamos agora escrever o método pegaNomeDoItem, veja
como ficou logo abaixo:

21| private fun pegaNomeDoItem() {


22|  
val nomeItemTextView = findViewById<Tex-
tView>(R.id.itemNomeTextView)
23|  nomeItemTextView.text = ListaDeCompras.
listaItens[itemIndice ?: 0].nome
24| }

Definimos este método chamado pegaNomeDoItem, sem a


necessidade de nenhum parâmetro, na linha 22, pegamos a refe-
rência do elemento do layout que possui o valor do atributo id,
armazenado na constante R.id.itemNomeTextView, utilizando
mais uma vez o método findViewById, atente ao fato que também
passamos o tipo deste elemento que é o TextView.
Lembre-se que a variável itemIndice, possui armazenado
o valor do índice do elemento que precisamos exibir neste campo
texto, por isso utilizamos a classe ListaDecompras, que defini-
mos como sendo um singleton, e acessamos o atributo lis-
taItems, veja que escrevemos um código novo aqui dado por
itemIndice ?: 0.

10-18
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Este código retorna o valor da variável ItemIndice caso
esse valor não seja nulo e caso contrário vai retornar o valor 0, cha-
mamos este operador de Elvis Operator, pois ele lembra o topete
do cantor Elvis Presley.
Feito isso pegamos o atributo nome deste elemento e arma-
zenamos no atributo text da variável nomeItemTextview, que
representa o elemento de layout do tipo TextView que vamos uti-
lizar para exibir o nome do item.
Vamos agora escrever o último método desta classe, que será
o defineBotaoComprado, veja abaixo como vai ficar:

27| private fun defineBotaoComprado() {


28|  
val botaoComprado = findViewById<But-
ton>(R.id.compradoButton)
29|  
val itemComprado = ListaDeCompras.lis-
taItens[itemIndice ?: 0].comprado
30|  
val tituloBotao = if(itemComprado)
“Desfazer” else “Comprado”
31|
32|   botaoComprado.text = tituloBotao
33|   botaoComprado.setOnClickListener {
34|   
ListaDeCompras.listaItens[itemIndice
?: 0].comprado = !itemComprado
35|    finish()
36|  }
37| }

10-19
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Logo no começo definimos a variável botaoComprado,
que vai armazenar uma referência para o elemento do layout
do tipo Button, ao qual modificamos o id para comprado-
Button, para isso utilizamos mais uma vez o método find-
ViewById, passando o tipo Button e como parâmetro a constan-
te R.id.compradoButton.
Precisaremos também de uma referência para o item que
será marcado como comprado, por isso na linha 29 definimos a
variável itemComprado, novamente acessamos o atributo lis-
taItens diretamente da classe ListaDeCompras e passamos
como índice do item da lista a variável itemIndice, veja que no-
vamente utilizamos o operador?: que vai retornar 0 caso o valor da
variável itemIndice seja nulo.
Por fim pegamos o valor do atributo comprado, e teremos
então o valor deste atributo na variável itemComprado, lembre-
-se que este atributo é do tipo Boolean, ou seja, poderemos ter os
valores True ou False apenas.
Temos como objetivo, mudar o título do botão para o texto
Desfazer, caso o item já tenha sido comprado e caso o item não
tenha sido comprado vamos mudar o título deste botão para com-
prado, ou seja, o usuário poderá desmarcar o item caso ele mude
de ideia.
Portanto na linha 30, escrevemos uma condição que verifica
o valor da variável itemComprado é True, se for, retornamos a
String Desfazer, caso contrário se o valor da variável itemCom-
prado for False, então retornaremos a String Comprado, este
valor será armazenado na variável tituloBotao, e será atribuído
logo abaixo na linha 32 para a propriedade text do botão, fazendo
com que seu título mude conforme sua função.

10-20
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Temos agora que atribuir a função lambda que vai ser exe-
cutada quando o botão for clicado pelo usuário, faremos isso cha-
mando o método setOnClickListener e passando como pa-
râmetro a função definida pelas linhas 34, onde fazemos uso da
classe ListaDeCompras para acessar o atributo listaItens,
novamente utilizamos a variável itemIndice que possui o valor
do índice do elemento na lista juntamente com o operador ?:, e
modificamos o atributo comprado do elemento para a negação do
valor Booleano armazenado na variável itemComprado.
Neste caso, se o item já foi comprado, a variável itemCom-
prado possuirá valor True, como usamos o operador ! Estamos
mudando esse valor para False, ou seja, estamos desfazen-
do a compra.
Caso contrário, se o valor da variável itemComprado for
False, estaremos armazenando True no atributo comprado do
elemento, de maneira a marcar o elemento como comprado.
A última tarefa que esta função lambda vai executar é o mé-
todo finish, que irá terminar a VisualizaItemActivity.

10.6 Definindo o botão para adicionar itens


Agora que definimos a classe AdicionaItemActivity
precisamos de um meio de fazer com que ela seja lançada na tela
para que o usuário possa entrar com o nome e a quantidade do
novo item que vai ser cadastrado na lista de compras.
Para isso vamos voltar ao código da classe MainActivity,
que possui no layout um elemento do tipo FloatingActionBut-
ton, e criar o método defineBotaoAdicionaItem, veja como vai
ficar o código deste método logo abaixo:

10-21
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
1| private fun defineBotaoAdicionaItem() {
2|  
val adicionaItemFloatButton = find-
ViewById<FloatingActionButton>(R.
id.adicionaItemFloatButton)
3|   adicionaItemFloatButton.setOnClickListener {
4|   
val adcionaItemIntent = Intent(this,
AdicionaItemActivity::class.java)
5|   startActivity(adcionaItemIntent)
6|  }
7| }

A primeira coisa que faremos neste método é pegar a refe-


rência uma referência para o FloatingActionButton que pos-
sui o id referenciado pela constante R.id.adicionaItemFloa-
tButton, este é o botão com o sinal de adição que definimos no
layout da MainActivity.
Com a referência para este elemento armazenada na variável
adicionaItemFloatButton, podemos chamar o método se-
tOnClickListener, e passar como parâmetro a função lambda
que vai ser executada quando o usuário clicar no botão.
A função lambda começa a ser definida na linha 4 pela criação
de um objeto do tipo Intent, criamos este objeto passando como
primeiro parâmetro no construtor a referência dessa instância da
classe MainActivity representada pela palavra chave this, e
na sequência, como segundo parâmetro passamos uma referência
para a classe AdicionaItemActivity.
Para isso fizemos o uso da chamada AdicionaItemActi-
vity::class.java, note que fizemos o uso do operador ::, este
operador em Kotlin quando aplicado no nível de classe faz uma

10-22
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
reflexão e retorna uma referência para a classe que estamos usan-
do como operando, isso fará com que o objeto adicionaItemIn-
tent, fique associado a AdicionaItemAcitvity, por fim bas-
ta chamarmos o método startActivity, como feito na linha 5
para lançarmos a AdicionaItemActivity.

10.7 Definindo o botão para remover todos os itens


Devemos também definir a ação do clique para o botão do
canto esquerdo do layout da MainActivity, este botão vai remo-
ver todos os itens da lista de uma só vez, veja abaixo como vai ficar
o código do método defineBotaoRemoverTodos.

1| private fun defineBotaoRemoverTodos() {


2|  
val removeTodosFloatButton = find-
ViewById<FloatingActionButton>(R.
id.removerTodosFloatButton)
removeTodosFloatButton.setOnClickListener {
3|  
4|   ListaDeCompras.removerTodosItens()
5|   atualizaListaDeCompra()
6|  }
7| }

Precisaremos de uma referência do FloatingAc-


tionButton que possui o sinal de negativo e foi definido
no canto inferior esquerdo da MainActivity, para isso uti-
lizamos novamente o método findViewById passando como

10-23
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
parâmetro a constante que faz referência a esse elemento que é a
R.id.removerTodosFloatButton.
Com esta referência armazenada na variável imutável cha-
mada removeTodosFloatButton, chamamos o método setOn-
ClickListener, e passamos como parâmetro a função lambda
definida nas linhas 4 e 5.
Já na linha 4 chamamos o método removerTodosItens da
classe ListaDeCompras que é um singleton e na sequência,
na linha 5 chamamos o método atualizaListaDeCompra, para
que a listaDecomprasRecycleView, seja atualizada e os itens
não sejam mais mostrados.

10.8 Finalizando a MainActivity


Chegou o momento de definirmos o método onCreate da
MainActivity pois agora temos ambos os métodos defineBo-
taoAdicionaItem e defineBotaoRemoverTodos, veja abaixo
como ficou o código:

1| override fun onCreate(savedInstanceSta-


te: Bundle?) {
2|  super.onCreate(savedInstanceState)
3|  setContentView(R.layout.activity_main)
listaDecomprasRecycleView = findViewById<Recy-
4|  
clerView>(R.id.listaDeComprasRecyclerView)
5|   defineBotaoAdicionaItem()
6|   defineBotaoRemoverTodos()
7| }

10-24
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 10

V IS U A LIZA N D O E A D IC IO N AN D O ITEN S
Toda a vez que o usuário abrir o aplicativo o método on-
Create da MainActivity será executado, na linha 3, o
método cria todos os elementos que foram definidos no ar-
quivo activity_main.xml.
É neste método que precisamos criar uma referência para
o elemento do tipo RecyclerView que foi definido no layout,
para isso utilizamos o método findViewById e passamos como
parâmetro a constante R.id.listaDeComprasRecyclerView,
que faz referência a esse elemento.
Armazenaremos esta referência no atributo de classe chama-
do listaDecomprasRecycleView. Feito isso, precisamos ainda
definir a ação para o botão que adiciona um item na lista e para
o botão que remove todos os itens da lista, por isso chamamos o
método defineBotaoAdicionaItem na linha 5 e o método de-
fineBotaoRemovertodos na linha 6.

10-25
 EXERCÍCIOS PROPOSTOS

1) Sobre o arquivo activity_adiciona_item.xml, escolha a alternativa correta:

(  ) -a) Este arquivo vai armazenar o código escrito em Kotlin que


define a Activity que vai gerenciar a tela de adição de itens
na lista.
(  ) -b) Este arquivo vai armazenar o layout dos elementos da tela de
adição de itens na lista.
(  ) -c) Não podemos criar mais um arquivo .xml pois devemos usar
o arquivo activity_main.xml
(  ) -d) Este arquivo deverá ser armazenado em app/drawable
(  ) -e) N.d.a

2) Sobre o arquivo AdicionaItemActivity.kt, escolha a alternativa correta:

(  ) -a) Este arquivo contém a classe AdicionaItemActivity, esta


classe pega dos campos nome e quantidade e cria um novo
item, que é adicionado na lista de itens mantida pela classe
ListaDeCompras.
(  ) -b) Este arquivo contém a classe AdicionaItemActivity que ape-
nas é utilizada para criar os elementos na tela.
(  ) -c) A classe AdicionaItemActivity, cria uma nova instância da
classe ListaDeCompras.
(  ) -d) Esta classe pega os dados do nome e da quantidade do item e
adiciona na lista de itens interna da classe ListaDeCompras,
porém esses dados são perdidos quando a AdicionaItemAc-
tivity, é terminada pelo método finish.
(  ) -e) Quando o método finish é chamado a aplicação inteira é
fechada.

10-26
3) Sobre o arquivo AndroidManifest.xml escolha a alternativa correta

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Este arquivo não é necessário e pode ser apagado do projeto.
(  ) -b) Não é necessário registrarmos neste arquivo as Activities do
aplicativo.
(  ) -c) Todo projeto Android possui um arquivo chamado Android-
Manifest.xml, neste arquivo é declarada a MainActivity e as
outras Activities, permissões sobre o uso da câmera e das
bibliotecas de localização também são declaradas neste
arquivo.
(  ) -d) Este arquivo não é criado automaticamente pelo Android
Studio.
(  ) -e) Este arquivo não pode ser lido, pois seu formato é binário.

4) Escolha a alternativa correta sobre a localização no projeto do arquivo


AndroidManifest.xml.

(  ) -a) App/res
(  ) -b) App/res/layout
(  ) -c) App/res/values
(  ) -d) App/manifests
(  ) -e) App/mipmap

5) Considere o código abaixo e escolha a alternativa correta:

1| fun onCreate(savedInstanceState: Bundle?) {


2|  super.onCreate(savedInstanceState)
3|   defineBotaoSalvar()
4| }

(  ) -a) O código acima não possui nenhum erro, e vai ser executado
assim que a Activity for lançada.
(  ) -b) O código acima possui apenas um erro, pois a palavra chave
override precisa vir antes da palavra fun na linha 1

10-27
(  ) -c) O código acima possui apenas um erro, pois ele deve chamar
o método setContentView para instanciar os elementos que

EX ER C ÍC IO S PR O PO STO S
foram definidos no arquivo activity_adiciona_item.xml.
(  ) -d) O código acima possui dois erros, na linha 1 antes da palavra
chave fun precisamos marcar o método com a palavra chave
override e logo após a linha 2 devemos inserir uma chamada
para o método setContentView, passando como referência a
constante R.layout.activity_adiciona_item.
(  ) -e) N.d.a.

6) Quando queremos aumentar o tamanho do texto de um elemento do tipo


TextView, qual atributo devemos modificar?

(  ) -a) Text
(  ) -b) Id
(  ) -c) AutoText
(  ) -d) Capitalize
(  ) -e) TextSize

7) Considere a classe VisualizaItemActivity, e escolha a alternativa abaixo


que contém a afirmação correta:

(  ) -a) A variável itemIndice representa o índice do item que foi es-


colhido na lista da MainActivity e será utilizada para acessar
o item correto na lista ListaDeCompras.listaItens.
(  ) -b) A variável ItemIndice recebe o valor do índice do item se-
lecionado por meio de um parâmetro do método onCreate.
(  ) -c) A expressão itemIndice ?: 0 vai sempre retornar o valor 0.
(  ) -d) Podemos remover a variável ItemIndice, pois o índice do
item selecionado está no singleton ListaDeCompras.
(  ) -e) A expressão intent.extras?.getInt(“itemIndice”,0) pode re-
sultar num crash do aplicativo.

8) Considere o código abaixo, e escolha a alternativa correta:

1| botaoComprado.setOnClickListener {

10-28
2|  ListaDeCompras
.listaItens[itemIndice ?: 0]

EX ER C ÍC IO S PR O PO STO S
.comprado = !itemComprado
3|   finish()
4| }

(  ) -a) O código acima está errado pois devemos usar apenas pa-
rênteses para passarmos os parâmetros e não chaves.
(  ) -b) O método finish não foi implementado, e vai causar um erro
de compilação.
(  ) -c) O código acima faz com que quando o botão comprado do
layout receber um clique o item irá mudar o seu estado
de comprado para true caso ele seja false e para false caso
ele seja true e a VisualizaItemActivity vai continuar sendo
apresentada.
(  ) -d) O código acima faz com que quando o botão comprado do
layout receber um clique o item irá mudar o seu estado de
comprado para true caso ele seja false e para false caso ele
seja true e a VisualizaItemActivity vai ser fechada pois o mé-
todo finish foi chamado na linha 3.
(  ) -e) N.d.a.

9) Considere o código abaixo e escolha a alternativa correta:

1| private fun pegaNomeDoItem() {


2|  val nomeItemTextView = findViewById<Tex-
tView>(R.id.itemNomeTextView)
3|  nomeItemTextView.text = ListaDeCompras.
listaItens[itemIndice ?: 0].nome
4| }

(  ) -a) O método acima vai gerar um erro de execução, pois caso o


usuário clique na linha e nenhum item estiver selecionado a
ListaDeCompras.listaItens vai estar vazia.
(  ) -b) Este método define uma variável que faz referência ao ele-
mento TextView pela constante R.id.itemNomeTextView, e

10-29
na linha 3 modifica o atributo text para ter o valor do nome
do item que foi selecionado na lista da MainActivity.

EX ER C ÍC IO S PR O PO STO S
(  ) -c) Não podemos definir a variável nomeItemTextView com a
palavra chave val, pois vamos modificar o atributo text na
linha 3.
(  ) -d) Não precisamos usar o operador ?: pois a variável itemIndi-
ce nunca vai ser nula.
(  ) -e) Não podemos definir o método pegaNomeDoItem como pri-
vate pois este método será chamado pela MainActivity.

10) Como o valor da posição do item na lista é passado da MainActivity para


a VisualizaItemActivity ?

(  ) -a) Na classe MainActivity devemos criar uma instância da


classe VisualizaItemActivity, e setar o valor da variável
itemIndice.
(  ) -b) Devemos criar uma variável global e armazenar este valor para
que ele possa ser acessado pela classe VisualizaItemActivity.
(  ) -c) Na classe LinhaLista devemos armazenar este valor usando
a chave itemIndice no intent que será usado como parâme-
tro no método startActivity. E na classe VisualizaItemActivi-
ty, utilizamos o método getInt do atributo extras do inent, e
armazenar este valor na variável itemIndice.
(  ) -d) É passado pelo intent que é usado como parâmetro para o
método startActivity na MainActivity.
(  ) -e) N.d.a.

10-30
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

UNIDADE 6:
PERSISTÊNCIA NO APLICATIVO LISTA
DE COMPRAS

Caro(a) Aluno(a)
Seja bem-vindo(a)!

Nesta unidade veremos como adicionar uma camada de per-


sistência de dados ao projeto lista de compras, fazendo com que
os itens que o usuário adicionar sejam persistidos no sistema de
arquivos do dispositivo.
Faremos essa implementação utilizando a biblioteca Room do
Android que nos fornece um ORM.

Ótimos estudos!

Conteúdos da Unidade:
Adicionando suporte para a biblioteca Room, Criando modelo
de dados, Criando o Data Access Object, Criando a classe Room-
DataBase, Apresentando o objeto Executor, Apresentando o ob-
jeto Handler, Criando um parâmetro lambda para uma função,
Introdução ao conceito de Threads.
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 11:
CRIANDO A CAMADA DE PERSISTÊNCIA
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
11.1 Introdução
Quando inserimos alguns itens no aplicativo desenvolvido
na unidade anterior e em seguida fechamos este aplicativo perce-
beremos que todos os itens inseridos vão desaparecer.
Isso acontece pois estamos mantendo os dados cadastrado
na lista apenas em memória, pois olhando o código, veremos que
os itens da lista estão todos armazenados no atributo listaI-
tens, da classe ListaDeCompras, consequentemente, quando o
aplicativo sai da memória RAM do dispositivo, esta lista será desa-
locada, e os dados serão perdidos para sempre.
Para adicionar a funcionalidade de persistir os dados do apli-
cativo vamos fazer uso da biblioteca do android chamada Room.
Esta biblioteca fornece um mapeamento entre objetos definidos na
memória e tabelas em um banco de dados, este tipo de funcionali-
dade é chamado de ORM (Object Relational Map).

11.2 Adicionando a biblioteca Room ao projeto


Para começarmos a utilizar a biblioteca Room, antes de mais
nada, precisamos adicioná-la ao projeto, para isso precisamos mo-
dificar o arquivo build.gradle, primeiro vamos modificar sec-
ção plugins, como mostrado abaixo:

1| plugins {
2|   id ‘com.android.application’
3|   id ‘kotlin-android’
4|   id ‘kotlin-kapt’
5|   id ‘kotlin-android-extensions’
6| }

11-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
Depois de feita essa modificação clique no quinto contando da
direita para a esquerda na barra de ferramentas do Android Studio, o
hint deste botão é “Sync Project With Gradle Files”, isso
é necessário pois o Gradle vai baixar as dependências necessárias.
Além da secção plugins, devemos também modificar a
secção dependencies adicionando as duas últimas linhas, como
mostrado abaixo:

1| dependencies {
2|
implementation ‘androidx.core:core-ktx:1.6.0’
3|  
4|  implementation ‘androidx.
appcompat:appcompat:1.3.1’
5|  implementation ‘com.google.android.
material:material:1.4.0’
6|  implementation ‘androidx.cons-
traintlayout:constraintlayout: 2.1.1’
7|   testImplementation ‘junit:junit:4.+’
8|  androidTestImplementation ‘androidx.
test.ext:junit:1.1.3’
9|  androidTestImplementation ‘androidx.
test.espresso:espresso-core:3.4.0’
implementation ‘androidx.room:room-ktx:2.3.0’
10|  
11|  kapt “androidx.room:room-compiler:2.3.0”
12| }

11-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
Como dito anteriormente clique no quinto botão da direita
para esquerda que contém o hint “Sync Project With Gra-
dle Files”.

11.3 Adicionando o modelo de dados


Para utilizarmos a biblioteca Room precisamos definir um
modelo de dados, lembre-se que estamos trabalhando com um
ORM portanto vamos definir uma classe que será mapeada para
uma tabela.
Vamos mudar o nome da classe ItemLista para Item, é
muito fácil fazer isso, no navegador de projetos, que está no lado
esquerdo da tela do Android Studio vá até app/java/com.se-
gundo.listadecompras/modelo e clique com o botão direito
do mouse sobre o arquivo Item, escolha a opção Refactor e de-
pois a opção Rename, no campo texto que vai abrir coloque o novo
nome que será Item e clique no botão Refactor.
O Android Studio vai modificar o nome da classe e todos os
outros pontos do código que fazem referência a ela. Feito isso mo-
difique a classe para que ela fique como o código abaixo, novamen-
te vamos omitir as linhas de importação para economizar espaço:

1| @Entity
2| data class Item(@NonNull
3| @PrimaryKey(autoGenerate = true)
4| var id: Long?,
5| val qtd: Int,
6| val nome: String,

11-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
7| var comprado: Boolean) {
8| }

Na linha 1 escrevemos a anotação @Entity, isso faz com que


a biblioteca Room entenda que a classe Item será considerada uma
entidade e consequentemente será mapeada para uma tabela no
banco de dados.
É considerado uma boa prática, toda a tabela em um banco de
dados possuir um campo chamado de chave primária, este campo
não poderá ser nulo e seu valor deverá ser único para cada registro.
Novamente na linha 2 dentro do construtor utilizamos a
anotação @NotNull, que vai marcar o campo id como sendo não
nulo e na sequência a anotação @PrimaryKey(autoGenerate
= true), que vai fazer com que o próprio banco de dados gere
os valores para a chave primária, feito isso podemos considerar o
atributo id, do tipo Long? como sendo a chave primária da nossa
entidade Item.
Escolhemos o tipo Long? pois a biblioteca Room precisa des-
te tipo para prover os valores auto gerados, e usamos o símbolo?
pois quando construímos um objeto do tipo Item podemos omitir
o parâmetro id pois como este atributo será auto gerado não há
necessidade dele no construtor.
Por fim mantemos os atributos qtd, nome e comprado como
implementado anteriormente. Veja que no caso do modelo de da-
dos as modificações foram mínimas.

11-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
11.4 Adicionando o Data Access Object
É também exigido pela biblioteca Room que criemos uma in-
terface para representar o DAO que significa Data Access Ob-
ject, é por meio desta classe que a biblioteca Room vai fazer as
operações de inclusão, alteração, remoção e leitura dos dados ar-
mazenados no banco.
É muito comum darmos a essas operações o nome de CRUD,
que na língua inglesa significa Create, Read, Update e Delete.
Para isso vamos criar uma interface chamada ItemDao, no pacote
modelo do projeto e escrever o seguinte código:

1| @Dao
2| interface ItemDao {
3|
4|  @Insert
5|   fun insere(item: Item)
6|
7|  
@Query(“SELECT * from Item order by
nome asc”)
8|   fun pegaTodosItens(): MutableList<Item>
9|
10|   @Query(“DELETE from Item”)
11|   fun deleteTodos()
12|
13|  
@Query(“UPDATE Item SET comprado=:com-
prado WHERE id = :id”)

11-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
14|  
fun atualizaItem(comprado: Boolean, id: Long)
15| }

Inicialmente na linha 1, precisamos marcar a definição da


interface com a anotação @Dao, isso informa a biblioteca Room de
que esta interface será o nosso Data Access Object.
Na sequência na linha 4, utilizamos a anotação @Insert,
para identificar que o método insere, que recebe como parâme-
tro um objeto do tipo Item será utilizado quando queremos inserir
um item, veja que a biblioteca Room faz tudo automaticamente e
não precisamos nos preocupar em ficar acessando os dados do ob-
jeto item pelos atributos.
Para a operação de leitura, na linha 7 utilizamos a anotação
@Query e escrevemos o código SQL que pega todos os registros da
tabela Item ordenados pelo campo nome da letra a até a letra z.
E na linha 8 escrevemos o método chamado pegaTodosItens,
que não recebe nenhum parâmetro e retorna uma lista de objetos
do tipo Item. Este método será chamado quando quisermos pegar
todos os dados da tabela Item.
Agora na linha 11 temos o método deleteTodos, que vai
remover todos os registros da tabela item, veja que na linha 10 este
método foi marcado pela anotação @Query, que recebe como pa-
râmetro o código SQL que deleta todos os registros.
Por fim, precisamos de uma operação de atualização, pois
uma das funcionalidades do aplicativo é mudar o atributo compra-
do quando o usuário clica no botão da Activity de visualização.
Para isso novamente utilizamos a anotação @Query e pas-
samos como parâmetro para esta anotação o código SQL que
atualiza o campo atributo. Na sequência definimos o método

11-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
atualizaItem, que vai receber como primeiro parâmetro um
tipo Boolean indicado se o item foi comprado ou não, e como se-
gundo parâmetro o id do item.

11.5 A classe RoomDatabase


Agora que já definimos a entidade e a classe que representa
o DAO, precisamos de mais uma última classe que será responsável
por fazer a conexão com o banco de dados para isso criamos uma
classe abstrata chamada ItemDatabase, veja abaixo como vai fi-
car o código desta classe:

1|  
@Database(entities = [Item::class], version = 1)
2| abstract class ItemDataBase: RoomDatabase() {
3|
4|   abstract fun itemDao(): ItemDao
5|
6|   companion object {
private var INSTANCIA: ItemDataBase? = null
7|   
8|   
fun pegaInstancia(context: Context):
ItemDataBase? {
9|     if (INSTANCIA == null) {
10|     
synchronized(ItemDataBase::class) {
11|      
INSTANCIA = Room.databaseBuilder
(context.applicationContext,
12|      ItemDataBase::class.java,
13|      “item.db”).build()

11-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
14|     }
15|    }
16|    return INSTANCIA
17|   }
18|  }
19| }

Na linha 1 utilizamos a anotação @Database, para esta ano-


tação devemos passar no parâmetro entities uma lista com to-
das as classes da aplicação que representam as entidades, no caso
da nossa lista de compras, temos apenas uma entidade chamada
Item. Devemos também passar como parâmetro um valor que vai
representar a versão do banco de dados do aplicativo, utilizamos o
valor literal 1 para este propósito.
Na sequência definimos a classe ItemDataBase, como sen-
do filha da classe RoomDataBase. Será por meio desta classe que
iremos acessar os métodos da ItemDao para fazermos as operações
de leitura, escrita, atualização e remoção. Para isso declaramos um
método abstrato chamado itemDao que não recebe nenhum parâ-
metro e retorna uma instância da nossa classe itemDao.
A classe ItemDataBase, também será um singleton, mas
vamos declarar ela de uma outra maneira, vamos usar a instrução
companion object, que indica ao Kotlin que o bloco de código
que estiver entre as chaves deverá ser considerado estático ou seja
mesmo que tivéssemos mais uma instância desta classe esse trecho
do código continuaria sendo único.
Neste contexto estático vamos declarar uma variável privada
chamada INSTANCIA do tipo ItemDataBase?, esta variável vai
armazenar a referência para a instância única da classe.

11-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 11

C R IA N D O A C A MA D A D E PER SISTÊ N CI A
Na sequência vamos definir o método pegaInstancia, este
método será responsável por criar apenas uma instância da classe
ItemDataBase, e armazenar a referência para essa instância na
variável INSTANCIA.
Dentro do método pegaInstancia, temos uma condição
que verifica se a variável INSTANCIA é nula, caso isso seja verda-
deiro, então uma instância da classe ItemDataBase será criada,
quando chamamos o método databaseBuilder da classe Room,
passando como primeiro parâmetro o context, que foi recebido
no método pegaInstancia.
O segundo parâmetro do databaseBuilder é a referência
da classe ItemDataBase, que passamos usando o operador refle-
xivo e por fim passamos a String item.db, que vai dar nome ao
arquivo do SQLite que será criado no dispositivo para armazenar
o banco de dados.
Caso contrário, na linha 9, se a expressão condicional retor-
nar o valor false, então sabemos que a variável INSTANCIA, já
possui uma referência para um objeto do tipo ItemDataBase,
portanto um novo objeto deste tipo não precisa ser instanciado,
o método pegaInstancia, apenas precisa retornar este objeto,
como é feito na linha 16.
No próximo capítulo iremos ver como usar toda essa nova
infraestrutura de persistência que foi criada, para armazenar os
itens de uma lista. Da mesma maneira como foi feita neste capítulo
iremos modificar uma parte do aplicativo lista de compras.

11-11
 EXERCÍCIOS PROPOSTOS

1) Qual a biblioteca do Android que utilizamos no projeto para fazer a per-


sistência dos dados do aplicativo?

(  ) -a) A biblioteca SQLite.


(  ) -b) A biblioteca Room.
(  ) -c) Não foi necessária nenhuma biblioteca.
(  ) -d) Fizemos a persistência usando apenas comandos SQL
(  ) -e) Utilizamos um arquivo texto para fazer a persistência.

2) O que significa a sigla ORM?

(  ) -a) Old Relational Map


(  ) -b) Odd Relational Map
(  ) -c) Object Reaction Map
(  ) -d) Object Relational Map
(  ) -e) Object Relational Method

3) Para que serve a anotação @Entity?

(  ) -a) Esta anotação é nativa do Android e serve para marcar uma


classe para que ela seja considerada uma tabela.
(  ) -b) Esta anotação é implementada pela biblioteca Room e ser-
ve para marcar a classe que será considerada como sendo a
Data Object Access.
(  ) -c) Esta anotação pertence à biblioteca Room, e é utilizada para
executarmos instruções SQL.
(  ) -d) Esta anotação pertence a biblioteca Room, e é utilizada para
marcarmos uma classe que será considerada como sendo
uma entidade e, portanto, será mapeada no banco de dados.
(  ) -e) N.d.a

11-12
4) Sobre a anotação @Dao, escolha a alternativa correta.

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Marcamos uma interface com esta anotação para que a bi-
blioteca Room utilize-a para manipular os dados, ou seja,
para que as funcionalidades do CRUD sejam feitas.
(  ) -b) A anotação @Dao é utilizada pela biblioteca Room para
marcar uma classe que será considerada como uma tabela.
(  ) -c) A sigla Dao significa, Data Alteration Object.
(  ) -d) Não podemos utilizar a anotação @Query dentro da interfa-
ce marcada com a anotação @Dao
(  ) -e) O elemento marcado com a anotação @Dao não pode ser
uma interface.

5) Considere o código abaixo e escolha a alternativa correta:

1| @Query(“UPDATE Item SET comprado=:com-


prado WHERE id = :id”)
2| fun atualizaItem(comprado: Boolean, id: Long)

(  ) -a) O código acima deverá ser escrito na classe marcada com @


Entity.
(  ) -b) O código acima está errado pois a anotação @Query não
existe na biblioteca Room.
(  ) -c) O código acima deverá ser escrito na interface marcada com
a anotação @Dao e servirá para inserir um novo item na
lista.
(  ) -d) Código acima deverá ser escrito na interface marcada com a
anotação @Dao e servirá para atualizar o atributo comprado
do item que possui o campo id passado como parâmetro no
método da linha 2.
(  ) -e) O código acima deverá ser escrito na interface marcada com
a anotação @Dao e servirá para atualizar todos os atributos
do objeto item.

11-13
6) Sobre a classe ItemDataBase escolha a alternativa verdadeira:

EX ER C ÍC IO S PR O PO STO S
(  ) -a) Não precisamos marcar esta classe com a anotação @
Database.
(  ) -b) Não é necessário termos uma referência para a interface
marcada com a anotação @Dao nesta classe.
(  ) -c) Esta classe não é um singleton.
(  ) -d) Esta classe é responsável por construir, versionar e dar aces-
so ao banco de dados que será armazendo num arquivo do
tipo SQLite.
(  ) -e) Para construirmos uma instância desta classe chamamos o
método estático databaseBuilder, que não precisa de uma
referência do application context.

7) Sobre a anotação @PrimaryKey(autoGenerate = true) escolha a alterna-


tiva correta:

(  ) -a) Esta anotação não pode ser utilizada na classe marcada pela
anotação @Entity
(  ) -b) O parâmetro autoGenerate = true, força que o aplicativo cui-
da do id da chave primária da tabela, de maneira a nunca
repetir este valor entre os registros cadastrados.
(  ) -c) A anotação @PrimaryKey(autoGenerate = true), garante
que o atributo id da tabela seja a chave primária e seu valor
auto gerado pelo banco de dados, de maneira que a aplica-
ção fique livre de controlar a lógica para esta finalidade.
(  ) -d) Apenas a anotação @PrimaryKey é necessária para que o
campo id seja considerado como chave primária e para que
seu valor seja auto gerado.
(  ) -e) A anotação PrimaryKey não pertence à biblioteca Room.

8) Considere o fragmento de código abaixo extraído do arquivo build.gradle


e escolha a alternativa correta:

1| plugins {
2|  :
3|  :

11-14
4|   id ‘kotlin-kapt’
5|   id ‘kotlin-android-extensions’

EX ER C ÍC IO S PR O PO STO S
6| }
7| :
8| :
36| dependencies {
37|  :
38|  :
45|  implementation ‘androidx.room:room-ktx:2.3.0’
46|   kapt “androidx.room:room-compiler:2.3.0”
47| }

(  ) -a) Não precisamos da linha 46 para que a biblioteca Room seja


corretamente importada.
(  ) -b) A linha 45 está errada, pois o código correto de importação é
android.room:room-ktx:2.3.0.
(  ) -c) As linhas 4 e 5 não são necessárias.
(  ) -d) As linhas inseridas no arquivo build.gradle estão corretas e
são responsáveis pela importação da biblioteca Room.
(  ) -e) Não precisamos modificar o arquivo build.gradle, pois a bi-
blioteca Room é importada automaticamente quando cria-
mos a aplicação.

9) Considere o código abaixo e escolha a alternativa correta:

1| @Query(“SELECT * from Item order by nome asc”)


2| fun pegaTodosItens(): MutableList<Item>

(  ) -a) O código acima pega todos os itens cadastrados na tabela


Item em qualquer ordem e por meio do método pegaTodosI-
tens retorna uma lista com todos estes itens.
(  ) -b) O código acima pega todos os itens cadastrados na tabela
Item em ordem ascendente, ou seja começando pela letra a
e indo até a letra z, e por meio do método pegaTodosItens
retorna uma lista com todos estes itens.

11-15
(  ) -c) A o texto que representa o código SQL na linha 1 está errado,
o correto seria: SELECT * from itemDatabase

EX ER C ÍC IO S PR O PO STO S
(  ) -d) Devemos escrever uma classe ItemDao que vai implementar
a interface ItemDao.
(  ) -e) N.d.a.

10) Considere o código abaixo e escolha a alternativa correta:

1| @Query(“DELETE from Item”)


2| fun deleteTodos()

(  ) -a) Este método é responsável por inserir um novo item no ban-


co de dados.
(  ) -b) Este método vai remover apenas o item cujo valor do id é o
mesmo do passado como parâmetro.
(  ) -c) Este código vai remover todos os registros da tabela de itens.
(  ) -d) Este código vai remover a tabela de itens.
(  ) -e) A query correta que deveria ser passado como parâmetro
para a anotação @Query deveria ser “DELETE from Item
where id = :id”

11-16
DISCIPLINA:

Desenvolvimento de Aplicativos
para Dispositivos Móveis

CAPÍTULO 12:
INTEGRANDO A CAMADA
DE PERSISTÊNCIA
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


12.1 Introdução
Neste capítulo vamos utilizar o modelo, o DAO e a classe
ItemDatabase para persistir os itens da lista de compras em
tabelas que farão parte de um banco de dados relacional. Vamos
iniciar modificando a classe ListaDeCompras, que está na cama-
da do modelo de dados e iremos subindo as modificações para a
camada de controle, você irá perceber que por termos seguido a
arquitetura MVC, teremos poucas modificações na camada contro-
ladora e nenhuma modificação na camada de visualização.

12.2 Modificando a classe ListaDeCompras


Antes de começarmos a modificar a classe ListaDeCom-
pras, é importante entendermos que o Android prioriza a execu-
ção de eventos da interface gráfica, ou seja, não podemos realizar
operações demoradas, como acesso ao sistema de arquivos, junto
com operações que recebem eventos do usuário, como cliques de
botão, navegação em lista entre outros.
Para contornar esta exigência deveremos fazer o proces-
samento das quatro operações de persistência, em uma linha de
processamento que seja diferente da que processa os elementos da
interface gráfica.
Vamos usar um objeto do tipo Executor que vai executar o
código e uma linha diferente de processamento e um outro objeto
do tipo Handler que vai pegar o resultado da execução e colo-
car na mesma linha de processamento dos elementos da interfa-
ce gráfica, que neste momento deverão ser atualizado pelos dados
já processados.

12-2
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Em computação o conceito de linhas de processamento é
amplamente estudado dentro do conceito de Threads, não iremos
mais a fundo pois fugiremos do escopo deste material.
Para uma melhor formatação vamos apenas colocar os tre-
chos iniciais da nova classe ListaDeCompras, e na sequência va-
mos detalhar cada um dos métodos dessa classe.

8| object ListaDeCompras {
9|
10|   var listaItens = mutableListOf<Item>()
11|
12|  
private val executor = Execu-
tors.newSingleThreadExecutor()
13|  
private val handler = Handler(Loo-
per.getMainLooper())
14|  :
15|  :
16| }

Manteremos a classe ListaDeCompras, como sendo um


singleton, por isso vamos manter a palavra chave object como
mostrado na linha 8. Da mesma maneira também vamos manter
a variável listaItens, fazendo isso não precisaremos modificar
as classes que controlam a RecyclerView, pois elas continuaram
pegando os itens cadastrados desta variável.
Precisaremos de um objeto do tipo Executor que utilizare-
mos para executar as operações do banco de dados fora da linha de
processamento dos elementos da interface gráfica, definimos esta

12-3
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


variável como com o nome de executor, na linha 12, utilizamos o
método estático da classe Executors para obtermos esta referência.
Na sequência definimos uma variável chamada handler, que
será responsável por atualizar os elementos da interface gráfica com
os dados que foram pegos no banco de dados, ou no caso de inse-
rirmos um novo item, utilizaremos esta variável para processar o
retorno de que a inclusão do item aconteceu para a interface gráfica.

12.3 Modificando o método que adiciona item na lista


Anteriormente como utilizamos apenas a variável listaI-
tens para armazenar os itens adicionados na lista, porém agora
vamos modificar este método para adicionarmos os itens no banco
de dados utilizando a biblioteca Room, veja abaixo como vai ficar o
novo código do método adicionarItemNaLista:

15| fun adicionarItemNaLista(item: Item,


context: Context, callBack: () -> Unit) {
16|   executor.execute {
17|   
val dataBase = ItemDataBase.
pegaInstancia(context)
18|   dataBase?.itemDao()?.insere(item)
19|   listaItens.add(item)
20|   handler.post {
21|    callBack()
22|   }
23|  }
24| }

12-4
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Logo na linha 15, modificamos a assinatura do método adi-
cionarItemNaLista, veja que agora, além do objeto do tipo
item que vamos inserir, vamos passar como segundo parâmetro
um objeto do tipo Context, pois ele será necessário para que a
biblioteca Room consiga abrir a conexão com o banco de dados
e por fim, como terceiro parâmetro passamos uma função cha-
mada callback.
A ideia de passarmos uma função como parâmetro é para
que possamos avisar o código que chamou este método de que a
operação terminou.
Na linha 16 vamos chamar o método execute do objeto
executor e usar o símbolo abre chaves { para indicar que o có-
digo abaixo deverá ser executado em uma linha de processamento
que não é a mesma dos componentes da interface gráfica, vamos
chamar essa linha de processamento é comumente chamada de
background thread.
Vamos definir a variável dataBase, que fará referência ins-
tância única do tipo ItemDatabase, fazemos isso chamando o
método estático desta classe chamado pegaInstancia, veja que
neste ponto utilizaremos o parâmetro context.
É na linha 18 que de fato, inserimos o novo item na lista, veja
que utilizando a variável dataBase, acessamos o atributo item-
Dao, que é o nosso meio de acessar as operações com os dados, e
por fim chamamos o método insere deste atributo, passando como
parâmetro o novo item.
Por baixo dos panos a biblioteca Room vai traduzir esta cha-
mada para um código SQL, e para isso ela também vai extrair do
objeto item todos os dados necessários para a criação deste código
SQL, veja quanta repetição de código foi poupada caso fossemos
fazer isso nós mesmos escrevendo todo esse código.

12-5
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Para manter a compatibilidade com as camadas superiores
do modelo MVC, na linha 19, também inserimos este objeto na lista
de itens referenciada pela variável listaItens, utilizando o mé-
todo add e passando como parâmetro o mesmo objeto item.
Neste ponto terminamos o trabalho de persistência dos da-
dos do novo item e podemos retornar ao método que chamou o
adicionarItemNaLista, mas precisamos fazer isso de modo
que voltemos a linha de execução da interface gráfica, ou comu-
mente chamada de user interface thread.
Para isso na linha 20, vamos chamar o método post do ob-
jeto handler, na sequência vamos usar o símbolo abre chaves {
e chamar a função que foi passada no atributo callback, perce-
ba que neste caso, estaremos devolvendo o processamento para a
user interface thread e o método chamador poderá acessar
os elementos da interface gráfica com segurança.

12.4 Criando o método para pegar todos os itens da lista


Como anteriormente pegamos todos os itens da variável
listaItens não precisávamos pegar os itens utilizando um
método, apenas precisávamos de acessar a lista e pegar os itens
dela, porém, agora precisaremos acessar o banco de dados o que
justifica a criação de mais um método. Veja abaixo como vai ficar
este método.

26| fun pegaTodosItensDaLista(context: Con-


text, callBack: () -> Unit) {
27|   executor.execute {

12-6
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


28|   val dataBase = ItemDataBase.pegaInstancia
(context)
29|   
listaItens = dataBase?.itemDao()?.
pegaTodosItens()!!
30|   handler.post{
31|    callBack()
32|   }
33|  }
34| }

Vamos definir como primeiro parâmetro deste método um


objeto do tipo Context, que utilizaremos para pegar a instância
do banco de dados, definimos também o segundo parâmetro cha-
mado de callback como sendo uma função que será chamada
assim que os dados estiverem disponíveis
Como dito anteriormente precisamos acessar a backgrou-
nd thread, vamos fazer isso na linha 17, utilizando o método
execute do objeto executor, portanto novamente as linhas 28,
29 e 30 serão executadas na background thread.
Para pegarmos os itens já cadastrados precisamos de uma
referência para a classe ItemDataBase, por isso usamos o mé-
todo pegaInstancia, passando como parâmetro a variável que
possui o context.
É na linha 29, que de fato pegamos todos os itens cadastra-
dos no banco de dados por meio do atributo itemDao e do método
pegaTodosItens. Novamente para não termos que gerar mais
modificações nas camadas de controle e visualização, atribuímos a
variável listaItens os dados que estavam persistidos no banco.

12-7
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Feito isso podemos retornar ao método chamador mas para
isso precisamos voltar o processamento para a user interface
thread, novamente chamaremos o método post do objeto han-
dler, utilizamos o símbolo abre chave { e chamamos o método
referenciado pelo parâmetro de nome callback.

12.5 Criando o método para atualizar o item da lista


Implementamos no aplicativo uma lógica que mudava o es-
tado do atributo comprado do objeto item para true caso o usuá-
rio clicasse no botão comprado.
Mudávamos para false caso o valor deste objeto já fosse
true e o usuário clicasse novamente no botão. Com a adição da
persistência, precisamos cuidar para que este comportamento tam-
bém seja refletido no banco de dados, para isso criamos o método:

47| fun atualizaItemComprado(item: Item,


context: Context, callBack: () -> Unit) {
48|   executor.execute {
49|   
val dataBase = ItemDataBase.
pegaInstancia(context)
50|   dataBase?
    .itemDao()?
    .atualizaItem(
    item.comprado,
    item.id ?: 0)
51|   handler.post {

12-8
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


52|    callBack()
53|   }
54|  }
55| }

Como nos outros métodos, passamos como primeiro pa-


râmetro o item que será atualizado, o segundo parâmetro será o
context e o terceiro a função de callback.
Para chamar o método atualiza item, precisamos de uma
referência para o banco de dados, como feito anteriormente, cha-
maremos o método estático pegaInstancia, passando o con-
text como parâmetro. Armazenamos esta referência na variá-
vel dataBase.
Na linha 50 chamamos o método atualizaItem do atribu-
to itemDao, passando o valor do atributo comprado e o valor do
id do objeto.
Ao final do processo, chamamos o método post do objeto
handler, e passamos como parâmetro a função referenciada pelo
parâmetro chamado callback.

12.6 Modificando o método para remover todos itens


da lista
Por fim precisamos modificar o método removerTodosI-
tens, pois anteriormente este método apenas apagava os itens da
lista, porém agora teremos que remover os itens do banco de da-
dos, veja abaixo como vai ficar este método:

12-9
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


36| fun removerTodosItens(context: Context,
callBack: () -> Unit) {
37|   executor.execute {
38|   val dataBase = ItemDataBase.pegaInstancia
(context)
39|   dataBase?.itemDao()?.deleteTodos()
40|   listaItens.clear()
41|   handler.post {
42|    callBack()
43|   }
44|  }
45| }

Devemos modificar o método para receber dois parâmetros,


o primeiro será o context e o segundo a função que será chamada
quando a remoção dos registro terminar. Novamente precisaremos
de uma referência para o banco de dados e fazemos isso na linha
38, no código que está dentro do parâmetro do método execute do
objeto executor.
Com a referência ao banco de dados armazenado na variá-
vel dataBase, chamamos o método deleteTodos do atribu-
to itemDao, para de fato remover todos os elementos do banco
de dados.
Como mantemos a variável listaItens sincronizada como
banco de dados, na linha 40 também removemos todos os itens da
lista, como foi no código anterior.
Agora basta informarmos o método que chamou de que a
operação de remoção está completa, isso será feito pela chamada

12-10
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


da função referenciada pelo parâmetro callback dentro do blo-
co de código que serve como parâmetro do método post do ob-
jeto handler.

12.7 Modificando a camada controladora


Temos um impacto mínimo na camada controlado-
ra, pois modificamos todas as assinaturas dos métodos da
classe ListaDeCompras.
Vamos começar modificando o método defineBotaoSalvar
da classe AdicionaItemActivity, esse método vai ficar assim:

19| private fun defineBotaoSalvar() {


20|  
val botaoSalvar = findViewById<But-
ton>(R.id.salvarButton)
21|   botaoSalvar.setOnClickListener {
22|    val item = criaItemLista()
23|   
L istaDeCompras.adicionarItemNaLis-
ta(item, this){
24|     finish()
25|   }
26|  }
27| }

A modificação começa na linha 23, pois agora o método


adicionarItemNaLista precisa de mais dois parâmetros, um
deles é o context, que podemos passar utilizando a palavra chave

12-11
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


this, que representa a própria classe, e por último devemos pas-
sar o parâmetro callback, que é uma função lambda, e como é o
último parâmetro podemos fechar o parêntese e colocar a função
dentro dos símbolos abre chaves { e do símbolo fecha chaves }
Dentro da função lambda passada como sendo o parâmetro
callback fazemos uma chamada ao método finish como ante-
riormente, para terminar a Activity assim que o método adi-
cionarItemNaLista terminar.
Outro método da classe AdicionaItemActivity, que de-
vemos modificar é o criaItemLista, veja como esse método vai
ficar logo abaixo:

29| private fun criaItemLista(): Item {


30|  
val itemNomeTextView = findViewById<E-
ditText>(R.id.itemNomeEditText)
31|  
val itemQtdTextView = findViewById<Edit-
Text>(R.id.itemQtdEditText)
32|  
val itemNome = itemNomeTextView.text.
toString()
33|  val itemQtd = itemQtdTextView.text.toS-
tring().toInt()
return Item(null, itemQtd, itemNome, false)
34|  
35| }

A modificação neste método é bem simples, como foi neces-


sário adicionarmos o atributo id, na classe Item, precisamos pas-
sar o valor null como sendo o primeiro parâmetro do construtor,
note que isso foi feito na linha 34.

12-12
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Vamos agora fazer as modificações necessárias, para o supor-
te da persistência, na classe MainActivity, a primeira modifica-
ção que vamos fazer será no método onResume, lembrando que,
este método é sempre chamado quando a MainActivity se torna
visível para o usuário. Veja abaixo como vai ficar este método:

27| override fun onResume() {


28|  super.onResume()
ListaDeCompras.pegaTodosItensDaLista(this) {
29|  
30|   atualizaListaDeCompra()
31|  }
32| }

Agora, não basta apenas chamarmos o método atualiza-


ListaDeCompra, precisamos primeiro pegar todos os itens da
lista utilizando o método pegaTodosItensDaLista, da classe
ListaDeCompras. Para chamarmos este novo método, precisa-
mos passar como primeiro parâmetro o context, fazemos isso
usando a palavra chave this.
O último parâmetro deste método é uma função lambda,
como é o último parâmetro, podemos colocar sua referência para
fora do parênteses e por ser uma função vamos escrever o seu có-
digo entre { e }.
O código desta função de callback será apenas uma cha-
mada para o método atualizaListaDeCompras, como era feito
anteriormente, porém agora como temos duas threads devemos
colocar essa chamada como sendo um parâmetro para o mé-
todo pegaTodosItensDaLista.

12-13
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


Temos que modificar mais um método nesta classe que é
o defineBotaoRemoverTodos, veja abaixo como este método
vai ficar:

42| private fun defineBotaoRemoverTodos() {


43|  
val removeTodosFloatButton = findViewById
<FloatingActionButton>(R.id.remover
TodosFloatButton)
removeTodosFloatButton.setOnClickListener {
44|  
45|   
ListaDeCompras.removerTodosItens(this) {
46|    atualizaListaDeCompra()
47|   }
48|  }
49| }

Novamente na linha 45, devemos agora chamar o método


removerTodosItens, passando como primeiro parâmetro o
context, que é referenciado pela palavra chave this, e na sequ-
ência como feito anteriormente escrevemos a função lambda entre
os símbolos { e }.
Como o parâmetro callback é executado ao final da remo-
ção de todos os elementos do banco de dados, a função atuali-
zaListaDeCompra será chamada somente quando a tabela de
itens estiver vazia, e esse é o comportamento que queremos, pois
neste caso mostraremos a RecyclerView sem nenhum item.
O último método que precisamos modificar é o defineBo-
taoComprado da classe VisualizaItemActivity, veja abaixo
como este método vai ficar:

12-14
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


26| private fun defineBotaoComprado() {
27|  
val botaoComprado = findViewById<But-
ton>(R.id.compradoButton)
28|  
val itemComprado = ListaDeCompras.lis-
taItens[itemIndice ?: 0].comprado
29|  
val tituloBotao = if(itemComprado)
“Desfazer” else “Comprado”
30|
31|   botaoComprado.text = tituloBotao
32|   botaoComprado.setOnClickListener {
33|   
val item = ListaDeCompras.listaI-
tens[itemIndice ?: 0]
34|    item.comprado = !itemComprado
35|   
L istaDeCompras.atualizaItemCompra-
do(item,this) {
36|     finish()
37|   }
38|  }
39| }

Como dito anteriormente este método define a ação do botão


comprado e atualiza o atributo comprado, do objeto Item, mas
agora como queremos persistir essa informação, não podemos
apenas modificar diretamente na variável listaItens, mas sim
deveremos chamar o método atualizaItemComprado, passan-
do como primeiro parâmetro o objeto item com o atributo com-
prado modificado conforme a lógica definida anteriormente e na

12-15
< / > Desenvolvimento de Aplicativos para Dispositivos Móveis 12

IN TEG R A N D O A C A MA D A D E PER SISTÊ N CI A


sequência o parâmetro context que novamente será referenciado
pela palavra chave this.
O último parâmetro, é o callback, onde passaremos uma
função que será chamada assim que o item for atualizado no banco
de dados. Esta função apenas faz uma chamada para o método fi-
nish, e como anteriormente, a VisualizaItemActivity, será
terminada assim que o dado for armazenado.

12-16
 EXERCÍCIOS PROPOSTOS

1) Sobre a classe Executor, escolha a alternativa correta.

(  ) -a) Esta classe não é necessária na implementação da


persistência.
(  ) -b) Utilizamos diretamente a classe Executor para definirmos
em que uma porção do código rode na mesma thread dos
elementos da interface gráfica.
(  ) -c) Definimos uma variável chamada executor que aponta para
um objeto deste tipo, para que possamos executar o código
que faz o acesso ao banco de dados em uma thread de ba-
ckground, ou seja em uma thread que seja diferente da que
manipula os elementos da interface gráfica.
(  ) -d) A classe Executor não é nativa da plataforma Android e de-
verá ser importada, por meio de uma entrada no arquivo
gradle.build.
(  ) -e) A classe Executor não existe.

2) Sobre a classe Handler, escolha a alternativa correta.

(  ) -a) A classe Handler não foi usada na implementação da


persistência.
(  ) -b) Fizemos uma chamada ao método post utilizando uma vari-
ável do tipo Handler chamada de handler, e passamos como
parâmetro para este método uma função lambda que será
executada na thread que manipula os elementos da interface
de usuário.
(  ) -c) A classe Handler teve que ser importada por meio de entra-
das no arquivo gradle.build.
(  ) -d) O método post do objeto handler não pode ser usado para
executar código na mesma thread dos elementos da interfa-
ce gráfica.
(  ) -e) A classe Handler não existe.

12-17
3) Considere o código abaixo e escolha a alternativa correta

EX ER C ÍC IO S PR O PO STO S
1| fun pegaTodosItensDaLista(context: Con-
text, callBack: () -> Unit) {
2|   executor.execute {
3|   val dataBase = ItemDataBase.pegaInstancia
(context)
4|   listaItens = dataBase?.itemDao()?.pega
TodosItens()!!
5|   handler.post{
6|    callBack()
7|   }
8|  }
9| }

(  ) -a) A linha 4 possui um erro pois o operador !! não existe.


(  ) -b) A variável handler do tipo Handler não pode ser acessada de
uma thread de background.
(  ) -c) O método callback não foi implementado nesta classe.
(  ) -d) Todo o código das linhas 3 até 7 será executado na mesma
thread de que os elementos da interface gráfica.
(  ) -e) O método acima está correto pois executa as operações de
acesso a banco em uma thread de background e quando a
operação termina chama o método post do objeto handler
para executar o método callback na thread de UI.

4) Considere o código abaixo e escolha a alternativa correta

1| fun atualizaItemComprado(item: Item,


context: Context, callBack: () -> Unit) {
2|   executor.execute {
3|    val dataBase = ItemDataBase.pegaInstancia()
4|    dataBase?.itemDao()?.atualizaItem(i-
tem.comprado, item.id)

12-18
5|   handler.post {
6|    callBack()

EX ER C ÍC IO S PR O PO STO S
7|   }
8|  }
9| }

(  ) -a) O código acima está correto e não necessita de nenhuma


correção, ele atualiza o atributo comprado do item que foi
passado como parâmetro.
(  ) -b) O código acima possui apenas um erro na linha 3, pois o mé-
todo pegaInstancia da classe ItemDataBase precisa de um
parâmetro do tipo context.
(  ) -c) O código acima possui apenas um erro na linha 4 pois o tipo
do atributo id do objeto item é Long?, neste caso podemos
corrigir o código apenas utilizando o operador ?:.
(  ) -d) Existem dois erros no código acima, um está na linha 3, pois te-
mos que passar um parâmetro context para o método pegaIns-
tancia e o outro na linha 4 pois precisamos usar o operador ?:
para garantir que o valor passado como parâmetro não será nulo.
(  ) -e) N.d.a.

5) Considere o código abaixo e escolha a alternativa correta.

1| fun removerTodosItens(context: Context,


callBack: () -> Unit) {
2|   executor.execute {
3|   val dataBase = ItemDataBase.pegaInstancia
(context)
4|   dataBase.itemDao().deleteTodos()
5|   listaItens.clear()
6|  }
7| }

(  ) -a) O código acima está correto e vai remover todos os registros


da tabela item rodando o código numa thread de background.

12-19
(  ) -b) Existe apenas um erro neste código, pois na linha 3 devemos
usar o operador ? Para acessar o atributo itemDao e nova-

EX ER C ÍC IO S PR O PO STO S
mente para acessar o método deleteTodos.
(  ) -c) O código possui apenas um erro, pois não foi usado o método
post do objeto handler não foi usado para retornar o callback
na mesma thread que cuida dos elementos da interface gráfica.
(  ) -d) Existem dois erros neste código, um deles é o uso do ope-
rador ? na linha 4 e o segundo é o uso do método post do
objeto handler para chamar o método de callback na thread
dos elementos gráficos.
(  ) -e) Existe apenas um erro neste código que é a chamada do mé-
todo clear do objeto listaItens.

6) Considere o código abaixo e escolha a alternativa correta:

1| override fun onResume() {


2|  super.onResume()
3|   L i s t a D e C o m p r a s . p e g a T o d o s I t e n s D a -
Lista(this) {
4|   atualizaListaDeCompra()
5|  }
6| }

(  ) -a) O método onResume não precisa ser sobrescrito.


(  ) -b) Não há necessidade de modificar o método onResume pois
apenas a chamada para o método atualizaListaDeCompra é
suficiente.
(  ) -c) O método acima está correto e sempre que a MainActivity é
mostrada para o usuário a lista de itens é atualizada com os
itens que agora são persistidos.
(  ) -d) Não podemos passar a palavra chave this como parâmetro
para o método pegaTodosItensDaLista, pois esta palavra cha-
ve faz referência a MainActivity que não é do tipo Context.
(  ) -e) Não podemos chamar o método pegaTodosItensDaLista di-
retamente da classe ListaDeCompras, pois precisamos de
uma instância dela.

12-20
7) Considere o código abaixo e escolha a alternativa correta:

EX ER C ÍC IO S PR O PO STO S
1| private fun defineBotaoSalvar() {
2|  val botaoSalvar = findViewById<Button>
(R.id.salvarButton)
3|   botaoSalvar.setOnClickListener {
4|    val item = criaItemLista()
5|    L istaDeCompras.adicionarItemNaLis-
ta(item, this){
6|     finish()
7|   }
8|  }
9| }

(  ) -a) Na linha 5 não podemos passar a palavra chave this, como


parâmetro pois a AdicionaItemActivity não é do tipo Context.
(  ) -b) O código acima está correto e vai adicionar um novo item à
lista fazendo a sua correta persistência.
(  ) -c) Na linha 4 devemos substituir a palavra chave val, pela pa-
lavra chave var.
(  ) -d) Não podemos chamar o método finish por dentro da função
lambda passada como parâmetro.
(  ) -e) O método finish vai ser chamado em uma thread de
background.

8) Qual foi a classe que não precisou ter nenhum método modificado após a
inclusão da funcionalidade de persistência ?

(  ) -a) ListaDeCompras
(  ) -b) MainActivity
(  ) -c) VisualizaItemActivity
(  ) -d) LinhaLinhaLista
(  ) -e) AdicionaItemActivity

12-21
9) Qual camada do modelo MVC sofreu mais modificações depois da imple-

EX ER C ÍC IO S PR O PO STO S
mentação da funcionalidade de persistência?

(  ) -a) A camada de visualização.


(  ) -b) A camada de controle.
(  ) -c) A camada de modelo de dados.
(  ) -d) Nenhuma camada, pois apenas adicionando a bibliote-
ca. Room foi possível ter a funcionalidade de persistência
implementada.
(  ) -e) Nenhuma camada pois apenas uma pequena modificação no
arquivo gradle.build foi necessária.

10) Sobre o arquivo activity_adiciona_item.xml, após a implementação da


funcionalidade de persistência podemos afirmar que:

(  ) -a) Este arquivo precisou ser amplamente modificado pois é


nele que está escrito o modelo de dados.
(  ) -b) Este arquivo não sofreu nenhuma modificação pois a cama-
da de visualização não foi afetada pela funcionalidade de
persistência.
(  ) -c) Tivemos que incluir um novo campo para que o usuário for-
necesse o código do produto para alimentar a chave primária.
(  ) -d) Tivemos que modificar o código xml do botão salvar para
fazer com que ele apontasse agora para a nova infra que cria-
mos utilizando a biblioteca Room.
(  ) -e) N.d.a.

12-22
Š
REFERÊNCIAS

RESENDE, Kassiano. Kotlin com Android: Crie aplicativos de maneira


fácil e divertida, primeira edição. São Paulo: Casas do Código, 2018.

SILVA, Rafael Munhoz Almeida da, código fonte do aplicativo: Álco-


ol ou Gasolina, 2021. Disponível em: https://github.com/munhra/
AlcoolOuGasolina

SILVA, Rafael Munhoz Almeida da, código fonte do aplicativo: Lis-


ta de Compras, 2021. Disponível em: https://github.com/munhra/
ListaDeCompras/tree/master

SILVA, Rafael Munhoz Almeida da, código fonte do aplicativo: Lista de


Compras com persistência, 2021. Disponível em: https://github.com/
munhra/ListaDeCompras/tree/master

13-1
" GABARITO
Capítulo 1:
1) (d) 6) (c)
2) (d) 7) (d)
3) (c) 8) (b)
4) (a) 9) (a)
5) (c) 10) (c)

Capítulo 2:
1) (d) 6) (c)
2) (e) 7) (e)
3) (b) 8) (b)
4) (a) 9) (c)
5) (c) 10) (d)

Capítulo 3:
1) (d) 6) (b)
2) (a) 7) (d)
3) (d) 8) (e)
4) (b) 9) (b)
5) (c) 10) (a)

14-1
Capítulo 4:

G ABAR I TO
1) (d) 6) (c)
2) (e) 7) (d)
3) (d) 8) (b)
4) (c) 9) (b)
5) (e) 10) (a)

Capítulo 5:
1) (c) 6) (b)
2) (a) 7) (a)
3) (c) 8) (a)
4) (a) 9) (b)
5) (c) 10) (c)

Capítulo 6:
1) (e) 6) (e)
2) (a) 7) (e)
3) (b) 8) (d)
4) (c) 9) (d)
5) (b) 10) (e)

Capítulo 7:
1) (c) 6) (d)
2) (b) 7) (d)
3) (c) 8) (b)
4) (b) 9) (c)
5) (c) 10) (e)

14-2
Capítulo 8:

G ABAR I TO
1) (c) 6) (c)
2) (e) 7) (d)
3) (b) 8) (d)
4) (b) 9) (d)
5) (d) 10) (e)

Capítulo 9:
1) (c) 6) (c)
2) (c) 7) (b)
3) (d) 8) (a)
4) (b) 9) (e)
5) (a) 10) (a)

Capítulo 10:
1) (b) 6) (e)
2) (a) 7) (a)
3) (c) 8) (c)
4) (d) 9) (b)
5) (d) 10) (c)

Capítulo 11:
1) (b) 6) (d)
2) (d) 7) (c)
3) (d) 8) (d)
4) (a) 9) (b)
5) (d) 10) (c)

14-3
Capítulo 12:

G ABAR I TO
1) (c) 6) (c)
2) (b) 7) (b)
3) (e) 8) (d)
4) (d) 9) (c)
5) (d) 10) (b)

14-4
1º EDIÇÃO - 2021

Editora

SÃO PAULO/ SP

Você também pode gostar