Neste tutorial, você aprimora o aplicativo DiceRoller do último tutorial e aprende como adicionar e usar recursos de imagem em seu aplicativo. Você também aprenderá sobre a compatibilidade do aplicativo com diferentes versões do Android e como o Android Jetpack pode ajudar.
res
) e
os arquivos de compilação do Gradle. Neste tutorial, você cria o aplicativo DiceRoller iniciado no tutorial anterior e adiciona imagens de dados que mudam quando o dado é lançado. O aplicativo DiceRoller final se parece com este:
Se você não trabalhou no último tutorial, pode baixar o aplicativo inicial aqui: DiceRoller.
No final do último tutorial, você possuia um aplicativo que atualiza uma vista de texto com um número entre 1 e 6 cada vez que o usuário toca em um botão. No entanto, o aplicativo é chamado DiceRoller, não 1-6 Number Generator, então seria bom se os dados realmente parecessem dados. Nesta tarefa, você adiciona algumas imagens de dados ao seu aplicativo. Então, em vez de atualizar o texto quando o botão é pressionado, você troca uma imagem diferente para cada resultado da rolagem.
res
. A pasta drawable
é onde você deve
colocar todos os recursos de imagem para seu aplicativo. Já na pasta drawable
você pode encontrar
os recursos para os ícones do iniciador do aplicativo. DiceImages
para o Android Studio e para a
pasta drawable. Clique em OK. dice_1.xml
e observe o código XML para esta imagem. Clique no botão
Preview para obter uma prévia da aparência real desse drawable vetorial. Agora que você tem os arquivos de imagem de dados em sua pasta res/drawables
, pode acessar esses
arquivos a partir do layout e código do seu aplicativo. Nesta etapa, você substitui o TextView
que
exibe os números por um ImageView
para exibir as imagens.
activity_main.xml
se ainda não estiver aberto. Clique na guia
Text para visualizar o código XML do layout. <TextView>
. <ImageView>
com estes atributos: <ImageView
android:id="@+id/dice_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/dice_1" />
Use um ImageView
para exibir uma imagem em seu layout. O único atributo novo para este elemento é
android:src
, para indicar o recurso de origem da imagem. Nesse caso, uma fonte de imagem de
@drawable/dice_1
significa que o Android deve procurar nos recursos de drawable
(res/drawable
) para a imagem chamada dice_1
.
MainActivity
. Esta é a aparência da função rollDice()
até agora:
private fun rollDice() {
val randomInt = (1..6).random()
val resultText: TextView = findViewById(R.id.result_text)
resultText.text = randomInt.toString()
}
Observe que a referência a R.id.result_text
pode estar destacada em vermelho - isso porque você
excluiu TextView
do layout e esse ID não existe mais.
resultText
e defina sua
propriedade de texto. Você não está mais usando um TextView
no layout, então não precisa de
nenhuma das linhas. findViewByID()
para obter uma referência à nova ImageView
no layout por ID
(R.id.dice_image
) e atribua essa vista para uma nova variável diceImage
: val diceImage: ImageView = findViewById(R.id.dice_image)
when
para escolher uma imagem de dado específico com base no valor de
randomInteger
:val drawableResource = when (randomInt) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
Tal como acontece com os IDs, você pode fazer referência às imagens de dados na pasta drawable com os valores
na classe R
. Aqui, R.drawable
se refere à pasta drawable do aplicativo e
dice_1
é um recurso de imagem de dado específico dentro dessa pasta.
ImageView
com o método setImageResource()
e a referência à
imagem da matriz que você acabou de encontrar. diceImage.setImageResource(drawableResource)
Tudo em seu aplicativo funciona, mas desenvolver aplicativos é mais do que apenas ter um código que funcione. Você também deve entender como escrever aplicativos de bom desempenho e bom comportamento. Isso significa que seus aplicativos devem funcionar bem, mesmo se o usuário não tiver o dispositivo Android mais caro ou a melhor conectividade de rede. Seus aplicativos também devem continuar a funcionar sem problemas à medida que você adiciona mais recursos, e seu código deve ser legível e bem organizado.
Nesta tarefa, você aprenderá uma maneira de tornar seu aplicativo mais eficiente.
MainActivity
, se ainda não estiver aberto. No método rollDice()
, observe a
declaração da variável diceImage
: val diceImage : ImageView = findViewById(R.id.dice_image)
Como rollDice()
é o tratador de cliques para o botão Roll, toda vez que o usuário
toca nesse botão, seu aplicativo chama findViewById()
e obtém outra referência a este
ImageView
. Idealmente, você deve minimizar o número de chamadas para findViewById()
,
pois o sistema Android está pesquisando toda a hierarquia de vistas a cada vez, e essa operação é cara.
Em um pequeno aplicativo como este, não é um grande problema. Se você estiver executando um aplicativo mais
complicado em um telefone mais lento, chamar continuamente findViewById()
pode causar atrasos no
aplicativo. Em vez disso, é uma prática recomendada apenas chamar findViewById()
uma vez e
armazenar o objeto View
em um campo. Mantendo a referência à ImageView
em um campo
permite que o sistema acesse a View
diretamente a qualquer momento, o que melhora o desempenho.
onCreate()
, crie um campo para conter o ImageView
.
var diceImage : ImageView? = null
Idealmente, você inicializaria essa variável aqui quando ela for declarada ou em um construtor - mas as
atividades do Android não usam construtores. Na verdade, as vistas no layout não são objetos acessíveis na
memória até que tenham sido infladas no método onCreate()
, pela chamada de
setContentView()
. Você não pode inicializar a variável diceImage
até que isso
aconteça.
Uma opção é definir a variável diceImage
como anulável, como neste exemplo. Defina-o como
null
quando for declarado e, em seguida, atribua-o ao ImageView
real em
onCreate()
com findViewById()
. Isso complicará seu código, no entanto, pois agora você
deve verificar o valor null
toda vez que quiser usar diceImage
. Existe uma maneira
melhor.
diceImage
para usar a palavra-chave lateinit
e remova a
atribuição null
: lateinit var diceImage : ImageView
A palavra-chave lateinit
promete ao compilador Kotlin que a variável será inicializada antes que o
código chame qualquer operação nela. Portanto, não precisamos inicializar a variável para null
aqui, e podemos tratá-la como uma variável não anulável quando a usamos. É uma prática recomendada usar
lateinit
com campos que mantêm vistas exatamente dessa maneira.
onCreate()
, após o método setContentView()
, use findViewById()
para obter o ImageView
. diceImage = findViewById(R.id.dice_image)
rollDice()
que declara e obtém a ImageView
. Você
substituiu essa linha pela declaração de campo anterior. val diceImage : ImageView = findViewById(R.id.dice_image)
Agora você está usando dice_1
como a imagem inicial do dado. Em vez disso, digamos que você não
queira exibir nenhuma imagem até que o dado seja lançado pela primeira vez. Existem algumas maneiras de fazer
isso.
activity_layout.xml
na guia Text. <ImageView>
, defina o atributo android:src
como
"@drawable/empty_dice"
:android:src="@drawable/empty_dice"
A imagem empty_dice
foi uma das imagens que você baixou e adicionou à pasta drawable
.
Tem o mesmo tamanho que as outras imagens de dados, mas está vazio. Esta imagem é a que será mostrada quando o
aplicativo for iniciado pela primeira vez.
activity_layout.xml
, copie a linha android:src
e cole uma segunda cópia. Altere
a palavra "android" para "tools", para que seus dois atributos fiquem assim:android:src="@drawable/empty_dice"
tools:src="@drawable/empty_dice" />
Aqui, você alterou o namespace XML deste atributo do namespace android
padrão para o namespace
tools
. O namespace tools
é usado quando você deseja definir o espaço reservado para o
conteúdo do que é usado apenas na prévia ou no editor de design no Android Studio. Os atributos que usam o
namespace tools
são removidos quando você compila o aplicativo.
Os namespaces são usados para ajudar a resolver ambiguidades ao se referir a atributos que possuem o mesmo
nome. Por exemplo, esses dois atributos na etiqueta <ImageView>
possuem o mesmo nome
(src
), mas o namespace é diferente.
<LinearLayout>
na raiz do arquivo de layout e observe os dois
namespaces definidos aqui. <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
...
tools:src
na etiqueta ImageView
para dice_1
em vez
de empty_dice
:android:src="@drawable/empty_dice"
tools:src="@drawable/dice_1" />
Observe que a imagem dice_1
está no lugar agora o espaço reservado para a imagem na prévia.
Um dos melhores aspectos sobre o desenvolvimento para Android é o grande número de dispositivos em que seu código pode ser executado - do Nexus One ao Pixel, a fatores de forma como tablets, Pixelbooks, relógios, TVs e carros.
Quando você escreve para Android, você não escreve aplicativos separados para cada um desses diferentes dispositivos - mesmo os aplicativos que são executados em formatos radicalmente diferentes, como relógios e TVs, podem compartilhar código. Mas ainda existem restrições e estratégias de compatibilidade das quais você precisa estar ciente para oferecer suporte a tudo isso.
Nesta tarefa, você aprenderá como direcionar seu aplicativo para níveis específicos de API do Android (versões) e como usar as bibliotecas do Android Jetpack para oferecer suporte a dispositivos mais antigos.
No tutorial anterior, quando você criou seu projeto, você indicou o nível de API Android específico que seu aplicativo deve suportar. O sistema operacional Android tem diferentes números de versão com nomes de guloseimas saborosas que estão em ordem alfabética. Cada versão do sistema operacional vem com novos recursos e funcionalidades. Por exemplo, o Android Oreo foi fornecido com suporte para aplicativos Picture-in-picture, enquanto o Android Pie introduziu Slices. Os níveis de API correspondem às versões do Android. Por exemplo, API 19 corresponde ao Android 4.4 (KitKat).
Devido a uma série de fatores, incluindo o que o hardware pode suportar, se os usuários optam por atualizar seus dispositivos e se os fabricantes oferecem suporte a diferentes níveis de sistema operacional, os usuários inevitavelmente acabam com dispositivos que executam diferentes versões de sistema operacional.
Ao criar seu projeto de aplicativo, você especifica o nível mínimo de API que seu aplicativo suporta. Ou seja, você especifica a versão mais antiga do Android compatível com seu aplicativo. Seu aplicativo também tem um nível para o qual é compilado e um nível ao qual se destina. Cada um desses níveis é um parâmetro de configuração nos arquivos de compilação do Gradle.
android
na parte superior do arquivo build.gradle
. (O exemplo
abaixo não é a seção inteira, mas contém o que você está mais interessado neste tutorial). android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.android.diceroller"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
compileSdkVersion
. compileSdkVersion 28
Este parâmetro especifica o nível de API do Android que o Gradle deve usar para compilar seu aplicativo. Esta é a versão mais recente do Android que seu aplicativo pode suportar. Ou seja, seu aplicativo pode usar os recursos de API incluídos neste nível de API e inferior. Nesse caso, seu aplicativo oferece suporte à API 28, que corresponde ao Android 9 (Pie).
targetSdkVersion
, que está dentro da seção defaultConfig
:
targetSdkVersion 28
Este valor é a API mais recente com a qual você testou seu aplicativo. Em muitos casos, é o mesmo valor de
compileSdkVersion
.
minSdkVersion
. minSdkVersion 19
Este parâmetro é o mais importante dos três, pois determina a versão mais antiga do Android na qual seu aplicativo será executado. Dispositivos que executam o sistema operacional Android mais antigo do que este nível de API não podem executar seu aplicativo.
Escolhendo o nível mínimo de API para seu aplicativo pode ser um desafio. Defina o nível da API muito baixo e você perderá os recursos mais recentes do sistema operacional Android. Defina um valor muito alto e seu aplicativo somente poderá ser executado em dispositivos mais novos.
Ao configurar seu projeto e chegar ao ponto de definir o nível mínimo de API para seu aplicativo, clique em Help me choose para ver a caixa de diálogo API Version Distribution A caixa de diálogo fornece informações sobre quantos dispositivos usam diferentes níveis de sistema operacional e recursos que foram adicionados ou alterados nos níveis de sistema operacional. Você também pode verificar as notas de versão da documentação do Android e o painel, que contém mais informações sobre as implicações do suporte a diferentes níveis de API.
Escrevendo para diferentes níveis de API do Android é um desafio comum que os desenvolvedores de aplicativos enfrentam, portanto, a equipe de estrutura do Android fez muito trabalho para ajudá-lo.
Em 2011, a equipe lançou a primeira biblioteca de suporte, uma biblioteca desenvolvida pelo Google que oferece classes compatíveis com versões anteriores e funções úteis. Em 2018, o Google anunciou o Android Jetpack, uma coleção de bibliotecas que inclui muitas das classes e funções anteriores da biblioteca de suporte, além de expandir a biblioteca de suporte.
MainActivity
. MainActivity
se estende não da própria Activity
, mas de
AppCompatActivity
. class MainActivity : AppCompatActivity() {
...
AppCompatActivity
é uma classe de compatibilidade que garante que sua atividade tenha a mesma
aparência em diferentes níveis de sistema operacional de plataformas.
import
para expandir as
importações para sua classe. Observe que a classe AppCompatActivity
é importada do pacote
androidx.appcompat.app
. O namespace para as bibliotecas do Android Jetpack é
androidx
.dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
implementation 'androidx.core:core-ktx:1.0.1'
implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.1.0-alpha4'
}
Observe a dependência da biblioteca appcompat
, que faz parte do androidx
e contém a
classe AppCompatActivity
.
Você usará seu novo conhecimento sobre namespaces, Gradle e compatibilidade para fazer um ajuste final em seu aplicativo, o que otimizará o tamanho de seu aplicativo em plataformas mais antigas.
defaultConfig
:
vectorDrawables.useSupportLibrary = true
build.gradle
é modificado,
você precisa sincronizar os arquivos de construção com o projeto. activity_main.xml
. Adicione este namespace à etiqueta raiz
<LinearLayout>
, abaixo do namespace tools
: xmlns:app="http://schemas.android.com/apk/res-auto"
O namespace app
é para atributos que vêm de seu código customizado ou de bibliotecas e não da
estrutura Android principal.
android:src
no elemento <ImageView>
para ser
app:srcCompat
. app:srcCompat="@drawable/empty_dice"
O atributo app:srcCompat
usa a biblioteca Android X para oferecer suporte a drawables
vetoriais em versões anteriores do Android, de volta ao nível 7 da API.
Projeto Android Studio: DiceRollerFinal
Desafio: Modifique o aplicativo DiceRoller para ter dois dados. Quando o usuário toca no botão Roll, cada dado deve ter um valor independente do outro.
Dica: Crie uma função privada para obter uma imagem drawable aleatória e retornar um inteiro para o recurso drawable. Use essa função para cada uma das imagens da matriz.
private fun getRandomDiceImage() : Int { ... }
Projeto Android Studio: DiceRollerFinal-challenge
Recursos do aplicativo:
res
. drawable
é onde você deve colocar todos os recursos de imagem para seu
aplicativo.
Usando drawables vetoriais em vistas de imagens:
<ImageView>
. A
fonte da imagem está no atributo android:src
. Para referir-se à pasta de recursos drawable, use
@drawable
, por exemplo "@drawable/image_name"
.ImageView
em seu código MainActivity
para a imagem. Você pode usar
setImageResource()
para alterar a imagem da vista para um recurso diferente. Use
R.drawable
para referir-se a drawables específicos, por exemplo
setImageResource(R.drawable.image_name)
.A palavra-chave lateinit
:
findViewById()
em seu código, declarando campos para manter essas
vistas e inicializando os campos em onCreate()
. Use a palavra-chave lateinit
para o
campo para evitar a necessidade de declará-lo anulável.O namespace tools
para atributos de tempo de design:
tools:src
no elemento <ImageView>
em seu layout para exibir
uma imagem apenas na prévia ou no editor de design do Android Studio. Você pode então usar uma imagem vazia
para android:src
para o aplicativo final. tools
no arquivo de layout do Android para criar espaço reservado para conteúdo
ou dicas para layout no Android Studio. Os dados declarados pelos atributos tools
não são usados
no aplicativo final.Níveis de API:
compileSdkVersion
no arquivo build.gradle
especifica o nível de API do
Android que o Gradle deve usar para compilar seu aplicativo.targetSdkVersion
especifica o nível de API mais recente com o qual você testou seu
aplicativo. Em muitos casos, este parâmetro tem o mesmo valor que compileSdkVersion
.minSdkVersion
especifica o nível de API mais antigo em que seu aplicativo pode ser
executado. Android Jetpack:
androidx
referem-se às bibliotecas Jetpack. Dependências para
Jetpack em seu arquivo build.gradle
também começam com androidx
.Compatibilidade com versões anteriores para drawables vetoriais:
vectorDrawables.useSupportLibrary = true
no arquivo build.gradle
. app:srcCompat
no elemento <ImageView>
(em vez de android:src
) para especificar a fonte de
desenho vetorial para essa imagem. O namespace do app
:
app
em seu arquivo de layout XML é para atributos que vêm de seu código
personalizado ou de bibliotecas, não da estrutura Android principal.Documentação para desenvolvimento em Android:
ImageView
findViewById
()
De outros:
Esta seção lista as possíveis tarefas de casa para os alunos que estão trabalhando neste tutorial como parte de um curso ministrado por um instrutor.
Adicione um botão Clear ao aplicativo DiceRoller que define a imagem do dado de volta para a imagem vazia.
Qual atributo <ImageView>
indica uma imagem de origem que deve ser usada apenas no Android
Studio?
android:srcCompat
app:src
tools:src
tools:sourceImage
Qual método muda o recurso de imagem para um ImageView
no código Kotlin? xmx
setImageResource()
setImageURI()
setImage()
setImageRes()
O que a palavra-chave lateinit
em uma declaração de variável indica no código Kotlin?
null
. Qual configuração do Gradle indica o nível de API mais recente com o qual seu aplicativo foi testado?
minSdkVersion
compileSdkVersion
targetSdkVersion
testSdkVersion
Você vê uma linha de importação em seu código que começa com androidx
. O que isto significa?
Verifique se o aplicativo tem o seguinte:
R.drawable.empty_dice
.Comece a próxima lição:
Para obter enlaces para outros tutoriais neste curso, consulte a página de destino dos tutoriais Fundamentos de Android em Kotlin.