Share
Embed
Android Training Program - Portugal, Aula 5
Aula #5: Listas, listas e mais listas 🥞
Por vezes temos de carregar e processar dados bastante pesados. Como é que o conseguimos fazer sem que a nossa aplicação não bloqueie?
- RecyclerView
- Bibliotecas externas
- Retrofit
- Glide
- Paging 3
ATP Portugal
November 18, 2020
Transcript
127 slides
-
• Sejam excelentes uns para os outros • Fale mais
alto se vir ou ouvir alguma coisa • O assédio não é tolerado • Pratique "Sim e" um ao outro Código de conduta Mais informações: http://bit.ly/2IhF0l3 -
Andres-Leonardo Martinez-Ortiz Google Carlos Mota Formador Renato Almeida Formador @davilagrau
@cafonsomota @tallnato Equipa Daniela Ferreira Gestora de comunidades -
• 12 aulas • 1h30 cada aula • ~1 aula
por semana • 14 Outubro a 16 Dezembro • YouTube live • Suporte assíncrono contínuo via Discord/email • Todo o código disponível no GitHub Photo by Arif Riyanto on Unspla O programa -
#0 14 de Outubro Pronto para começar #1 21 de
Outubro Bem-vindos ao Android #2 28 de Outubro Fundações I #3 04 de Novembro Fundações II #4 11 de Novembro Fundações III #5 18 de Novembro Listas, listas e mais listas #6 25 de Novembro Jetpack, Jetpack, Jetpack! #7 - #8 02 - 03 de Dezembro Firebase #9 - #10 09 - 10 de Dezembro MLKit & TensorFlow #11 16 de Dezembro Resumo Semana Semana Calendário ✅ ✅ ✅ ✅ Direto ✅ -
Sumário Photo by Mika Baumeister on Unsplash • Resumo da
aula anterior • RecyclerView • Retrofit • Glide • Paging • Kotlin para principiantes • Sexta-Feira negra -
• Permite separar os dados da sua representação gráfica •
Está associado a uma Activity ou Fragment • Continua a ser executado mesmo que a aplicação não esteja visível • Permanece em memória quando uma Activity é reconstruída • Não deve aceder à interface gráfica da aplicação ViewModel -
• Padrão de desenvolvimento de software • Um objeto (Observable)
notifica os interessados (Observers) ◦ Quando este valor é alterado • Os interessados subscrevem para receber as atualizações Observável? Observable Observer Observer Observer ... -
atualizar atualizar atualizar atualizar desenha o ecrã desenha o ecrã
desenha o ecrã objetivo: 60fps UI-thread Operações assíncronas -
• A aplicação não é fluida ◦ Alguns frames podem
não ser desenhados • ANR podem ser lançados pelo sistema ◦ ANR = Activity Not Responding • Má experiência para o utilizador Operações assíncronas Counter isn’t responding -
• Service • Threads • IntentService • AsyncTasks • WorkManager
• JobScheduler • DownloadManager • AlarmManager • Coroutines Operações assíncronas Soluções -
Allow Snapchat to access this device’s location? Ao instalar todas
as permissões requisitadas são dadas Funcionalidades do sistemas precisam de autorização explícita do utilizador As permissões vão sendo cada vez mais restritivas: - Apenas enquanto estamos a utilizar a aplicação - Permitir apenas uma única vez Android ... Android 6.0 … Android 10 Android 11 -
Android 11 • Permissão única • O utilizador tem de
permitir o acesso contínuo à localização ◦ Maior segurança ◦ Poupança de bateria • Revogação de permissões para aplicações que não são utilizadas -
• É a evolução da ListView ◦ Com uma maior
performance e flexibilidade • Permite criar uma lista de objetos facilmente • Esta lista tanto pode ser horizontal como vertical ◦ Dependendo do LayoutManager definido • É possibilidade adicionar animações (incríveis) por cada item modificado RecyclerView -
RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter
ViewHolder data Adapter ViewHolder data -
RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter
ViewHolder data Adapter ViewHolder data -
dependencies { ... implementation "androidx.recyclerview:recyclerview:1.1.0" } Como utilizar? Importar a
biblioteca app/build.gradle -
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } Como utilizar? Criar uma Activity/Fragment MainActivity.kt -
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } Como utilizar? Criar uma Activity/Fragment MainActivity.kt ⚠ Não esquecer de a definir no AndroidManifest.xml -
<?xml version="1.0" encoding="utf-8"?> <LinearLayout ... <ImageView android:id="@+id/iv_user_image" android:layout_width="35dp" android:layout_height="35dp" android:layout_weight="0"
android:contentDescription="@string/description_user_profile" ndroid:scaleType="centerCrop"/> ... </LinearLayout> Como utilizar? … e como cada item deve ser res/layout/item_story.xml -
<?xml version="1.0" encoding="utf-8"?> <LinearLayout ... <ImageView android:id="@+id/iv_user_image" android:layout_width="35dp" android:layout_height="35dp" android:layout_weight="0"
android:contentDescription="@string/description_user_profile" ndroid:scaleType="centerCrop"/> ... </LinearLayout> Como utilizar? … e como cada item deve ser -
RecyclerView RecyclerView LayoutManager Adapter ViewHolder data Activity RecyclerView LayoutManager Adapter
ViewHolder data Adapter ViewHolder data -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context)
adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context)
adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context)
adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context)
adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context,
HORIZONTAL, false)) adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context,
HORIZONTAL, false)) adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
private fun setup() { findViewById<RecyclerView>(R.id.rv_feed).apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context,
HORIZONTAL, false)) adapter = FeedAdapter(Dogs.dogs) } } Como utilizar? Definir a RecyclerView na Activity MainActivity.kt -
RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter
ViewHolder data Adapter ViewHolder data -
class FeedAdapter constructor(val dogs: List<Dog>) : RecyclerView.Adapter<FeedAdapter.MainViewHolder>() { override fun
onCreateViewHolder(group: ViewGroup, type: Int): MainViewHolder override fun getItemCount(): Int override fun onBindViewHolder(holder: MainViewHolder, position: Int) } Como utilizar? Cria o Adapter FeedAdapter.kt -
class FeedAdapter constructor(val dogs: List<Dog>) : RecyclerView.Adapter<FeedAdapter.MainViewHolder>() { override fun
onCreateViewHolder(group: ViewGroup, type: Int): MainViewHolder { val inflater = LayoutInflater.from(parent.context) return MainViewHolder(inflater.inflate(R.layout.item_feed, parent, false)) } } Como utilizar? Cria o Adapter FeedAdapter.kt -
class FeedAdapter constructor(val dogs: List<Dog>) : RecyclerView.Adapter<FeedAdapter.MainViewHolder>() { override fun
onCreateViewHolder(group: ViewGroup, type: Int): MainViewHolder { val inflater = LayoutInflater.from(parent.context) return MainViewHolder(inflater.inflate(R.layout.item_feed, parent, false)) } override fun getItemCount() = dogs.size } Como utilizar? Cria o Adapter FeedAdapter.kt -
class FeedAdapter constructor(val dogs: List<Dog>) : RecyclerView.Adapter<FeedAdapter.MainViewHolder>() { override fun
onCreateViewHolder(group: ViewGroup, type: Int): MainViewHolder { val inflater = LayoutInflater.from(parent.context) return MainViewHolder(inflater.inflate(R.layout.item_feed, parent, false)) } override fun getItemCount() = dogs.size override fun onBindViewHolder(holder: MainViewHolder, position: Int) { val feed = dogs[position] holder.userImage.setImageResource(feed.picture) holder.userName.text = feed.name holder.image.setImageResource(feed.picture) } Como utilizar? Cria o Adapter FeedAdapter.kt -
class FeedAdapter constructor(val dogs: List<Dog>) : RecyclerView.Adapter<FeedAdapter.MainViewHolder>() { override fun
onCreateViewHolder(group: ViewGroup, type: Int): MainViewHolder { val inflater = LayoutInflater.from(parent.context) return MainViewHolder(inflater.inflate(R.layout.item_feed, parent, false)) } override fun getItemCount() = dogs.size override fun onBindViewHolder(holder: MainViewHolder, position: Int) { val feed = dogs[position] holder.userImage.setImageResource(feed.picture) holder.userName.text = feed.name holder.image.setImageResource(feed.picture) } class MainViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val userImage = itemView.iv_user_image!! val userName = itemView.tv_user_name!! val image = itemView.iv_image!! } } Como utilizar? Cria o Adapter FeedAdapter.kt -
• Cliente REST fortemente tipado • Facilita a transferência de
JSON através de um webservice ◦ JSON ou outro tipos de dados Retrofit https://github.com/square/retrofit -
Resultado da API { "bred_for": "Small rodent hunting, lapdog", "breed_group":
"Toy", "height": { "imperial": "9 - 11.5", "metric": "23 - 29" }, "id": 1, "life_span": "10 - 12 years", "name": "Affenpinscher", "origin": "Germany, France", "temperament": "Stubborn, Curious, Playful, Adventurous, Active, Fun-loving", "weight": { "imperial": "6 - 13", "metric": "3 - 6" } } data class Dog ( val bred_for : String, val breed_group : String, val height : Height, val id : Int, val life_span : String, val name : String, val origin : String, val temperament : String, val weight : Weight ) data class Height ( val imperial : String, val metric : String ) data class Weight ( val imperial : String, val metric : String ) -
Resultado da API "height": { "imperial": "9 - 11.5", "metric":
"23 - 29" } data class Height ( val imperial : String, val metric : String ) -
Resultado da API "weight": { "imperial": "6 - 13", "metric":
"3 - 6" } data class Weight ( val imperial : String, val metric : String ) -
Resultado da API { "bred_for": "Small rodent hunting, lapdog", "breed_group":
"Toy", "height": {...}, "id": 1, "life_span": "10 - 12 years", "name": "Affenpinscher", "origin": "Germany, France", "temperament": "Stubborn, Curious, Playful, Adventurous, Active, Fun-loving", "weight": {...} }, ... data class Dog ( val bred_for : String, val breed_group : String, val height : Height, val id : Int, val life_span : String, val name : String, val origin : String, val temperament : String, val weight : Weight ) -
Agora mais bonito ✨ { "bred_for": "Small rodent hunting, lapdog",
"breed_group": "Toy", "height": {...}, "id": 1, "life_span": "10 - 12 years", "name": "Affenpinscher", "origin": "Germany, France", "temperament": "Stubborn, Curious, Playful, Adventurous, Active, Fun-loving", "weight": {...} }, ... data class Dog( @Json(name = "bred_for") val bredFor: String, @Json(name = "breed_group") val breedGroup: String, val height: Height, val id: Int, @Json(name = "life_span") val lifeSpan: String, val name: String, val origin: String, val temperament: String, val weight: Weight ) -
• Biblioteca de conversão de JSON para Kotlin e Java
• Optimizada para Android • Compatível Retrofit Moshi -
dependencies { ... implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-moshi:2.9.0' } Como utilizar?
Importar a biblioteca app/build.gradle -
dependencies { ... def retrofitVersion = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" implementation
"com.squareup.retrofit2:converter-moshi:$retrofitVersion" } Como utilizar? Importar a biblioteca app/build.gradle -
interface DogApiClient { @GET("breeds") fun getBreeds() : Call<List<Dog>> } Como
utilizar? A interface DogApiClient.kt -
interface DogApiClient { @GET("breeds") fun getBreeds() : Call<List<Dog>> } Como
utilizar? A interface DogApiClient.kt Permite realizar trabalho em background -
class ApiProvider { private val retrofit = Retrofit.Builder() .baseUrl("https://api.thedogapi.com/v1") .addConverterFactory(MoshiConverterFactory.create())
.build() fun getDogApi(): DogApiClient { return retrofit.create<DogApiClient>() } } Como utilizar? A interface ApiProvider.kt -
class ApiProvider { private val retrofit = Retrofit.Builder() .baseUrl("https://api.thedogapi.com/v1/") .addConverterFactory(MoshiConverterFactory.create())
.build() fun getDogApi(): DogApiClient { return retrofit.create<DogApiClient>() } } Como utilizar? A interface ApiProvider.kt Por causa da inferência de tipo não precisamos de colocar o tipo -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
private val provider = ApiProvider() private val dogApi = provider.getDogApi()
fun getDogs() { dogApi.getBreeds() .enqueue(object : Callback<List<Dog>> { override fun onResponse(call: Call<List<Dog>>, response: Response<List<Dog>>) { if (response.isSuccessful) { val dogs = response.body() Log.d(TAG, "dogs $dogs") } } override fun onFailure(call: Call<List<Dog>>, t: Throwable) { Log.e(TAG, "Error loading dogs", t) } }) } Como utilizar? Obter os cães -
dogs [Dog(bredFor=null, breedGroup=null, height=Height(imperial=9 - 11.5, metric=23 - 29), id=1,
lifeSpan=null, name=Affenpinscher, origin=Germany, France, temperament=Stubborn, Curious, Playful, Adventurous, Active, Fun-loving, weight=Weight(imperial=6 - 13, metric=3 - 6)), Dog(bredFor=null, breedGroup=null, height=Height(imperial=25 - 27, metric=64 - 69), id=2, lifeSpan=null, name=Afghan Hound, origin=Afghanistan, Iran, Pakistan, temperament=Aloof, Clownish, Dignified, Independent, Happy, weight=Weight(imperial=50 - 60, metric=23 - 27)), Dog(bredFor=null, breedGroup=null, height=Height(imperial=30, metric=76), id=3, lifeSpan=null, name=African Hunting Dog, origin=, temperament=Wild, Hardworking, Dutiful, weight=Weight(imperial=44 - 66, metric=20 - 30)), Dog(bredFor=null, breedGroup=null, height=Height(imperial=21 - 23, metric=53 - 58), id=4, lifeSpan=null, name=Airedale Terrier, origin=United Kingdom, England, temperament=Outgoing, Friendly, Alert, Confident, Intelligent, Courageous, weight=Weight(imperial=40 - 65, metric=18 - 29)), Dog(bredFor=null, breedGroup=null, height=Height(imperial=28 - 34, metric=71 - 86), id=5, lifeSpan=null, name=Akbash Dog, origin=, temperament=Loyal, Independent... Resultado -
• Glide é uma biblioteca de carregamento de imagens para
Android • Rápida e eficiente • Código aberto, disponível no GitHub Glide https://github.com/bumptech/glide -
• Descarrega, descodifica e mostra ◦ Imagens ◦ GIF’s •
Permite também redimensionar imagens • Cache automática e simplificada das imagens • Expõe uma API flexível e simples de utilizar Vantagens -
• Permitir uma transição suave e rápido em qualquer tipo
de lista de imagens • Eficiente a carregar, redimensionar e descarregar imagens facilmente Objetivos -
• DiskCacheStrategy.ALL ◦ Faz cache de tudo • DiskCacheStrategy.AUTOMATIC ◦
Tenta escolher a melhor estratégia de forma inteligente de acordo com a origem • DiskCacheStrategy.DATA ◦ Faz cache da imagem original no disco antes de a descodificar • DiskCacheStrategy.NONE ◦ Não faz cache de nada • DiskCacheStrategy.RESOURCE ◦ Faz cache da imagem depois de algum processamento Estratégia de cache -
dependencies { ... implementation "com.github.bumptech.glide:glide:4.11.0" } Como utilizar? Importar a
biblioteca app/build.gradle -
// Em Activities Glide.with(activity) // Em Fragments Glide.with(fragment) // Ou
com o Context Glide.with(context) Como utilizar? No código Glide.with( ) .load(url) .into(imageView) -
• Versão melhorada e otimizada do seu antecessor - Paging
2 • Suporte direto para Kotlin e Flow • Permite carregamentos assíncronos • Muito mais simples de integrar • Facilidade de adicionar um item de carregamento ◦ Que indica o utilizador que novos dados estão a ser descarregados Paging 3 -
dependencies { ... implementation "androidx.paging:paging-runtime:3.0.0-alpha03" } Como utilizar? Importar a
biblioteca app/build.gradle -
class DogPagingSource(private val repository: Repository) : PagingSource<Int, Breed>() { override
suspend fun load(params: LoadParams<Int>): LoadResult<Int, Breed> { val nextPage = params.key ?: 1 val breeds = repository.getPagedBreedsList(nextPage) return LoadResult.Page( data = breeds, prevKey = if (nextPage == 1) null else nextPage -1, nextKey = nextPage + 1 ) } } Como utilizar? PagingSource DogsPagingSource.kt -
class DogPagingSource(private val repository: Repository) : PagingSource<Int, Breed>() { override
suspend fun load(params: LoadParams<Int>): LoadResult<Int, Breed> { val nextPage = params.key ?: 1 val breeds = repository.getPagedBreedsList(nextPage) return LoadResult.Page( data = breeds, prevKey = if (nextPage == 1) null else nextPage -1, nextKey = nextPage + 1 ) } } Como utilizar? PagingSource DogsPagingSource.kt -
class DogPagingSource(private val repository: Repository) : PagingSource<Int, Breed>() { override
suspend fun load(params: LoadParams<Int>): LoadResult<Int, Breed> { val nextPage = params.key ?: 1 val breeds = repository.getPagedBreedsList(nextPage) return LoadResult.Page( data = breeds, prevKey = if (nextPage == 1) null else nextPage -1, nextKey = nextPage + 1 ) } } Como utilizar? PagingSource DogsPagingSource.kt -
class ListViewModel: ViewModel() { private val repository = Repository() val
breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt -
class ListViewModel: ViewModel() { private val repository = Repository() val
breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt -
class ListViewModel: ViewModel() { private val repository = Repository() val
breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt -
class ListViewModel: ViewModel() { private val repository = Repository() val
breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt -
class ListActivity : AppCompatActivity() { val viewModel by viewModels<ListViewModel>() override
fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch{ viewModel.breedsListByPage.collect { val adapter = findViewById<RecyclerView>(R.id.rv_breeds).adapter as BreedsAdapter adapter.submitData(it) } } } } Como utilizar? Activity ListActivity.kt -
class ListActivity : AppCompatActivity() { val viewModel by viewModels<ListViewModel>() override
fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch{ viewModel.breedsListByPage.collect { val adapter = findViewById<RecyclerView>(R.id.rv_breeds).adapter as BreedsAdapter adapter.submitData(it) } } } } Como utilizar? Activity ListActivity.kt -
class ListActivity : AppCompatActivity() { val viewModel by viewModels<ListViewModel>() override
fun onCreate(savedInstanceState: Bundle?) { ... lifecycleScope.launch{ viewModel.breedsListByPage.collect { val adapter = findViewById<RecyclerView>(R.id.rv_breeds).adapter as BreedsAdapter adapter.submitData(it) } } } } Como utilizar? Activity ListActivity.kt -
class BreedsAdapter() : ListAdapter<Breed, BreedsAdapter.BreedsViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): BreedsViewHolder { val inflater = LayoutInflater.from(parent.context) return BreedsViewHolder(inflater.inflate(R.layout.item_breed, parent, false)) } override fun onBindViewHolder(holder: BreedsViewHolder, position: Int) { val breed = getItem(position) holder.breed.text = breed!!.name } } Como utilizar? Adapter BreedsAdapter.kt -
class BreedsAdapter() : ListAdapter<Breed, BreedsAdapter.BreedsViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): BreedsViewHolder { val inflater = LayoutInflater.from(parent.context) return BreedsViewHolder(inflater.inflate(R.layout.item_breed, parent, false)) } override fun onBindViewHolder(holder: BreedsViewHolder, position: Int) { val breed = getItem(position) holder.breed.text = breed!!.name } } Como utilizar? Adapter BreedsAdapter.kt -
class BreedsAdapter() : PagingDataAdapter<Breed, BreedsAdapter.BreedsViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): BreedsViewHolder { val inflater = LayoutInflater.from(parent.context) return BreedsViewHolder(inflater.inflate(R.layout.item_breed, parent, false)) } override fun onBindViewHolder(holder: BreedsViewHolder, position: Int) { val breed = getItem(position) holder.breed.text = breed!!.name } } Como utilizar? Adapter BreedsAdapter.kt -
class BreedsAdapter() : PagingDataAdapter<Breed, BreedsAdapter.BreedsViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): BreedsViewHolder { val inflater = LayoutInflater.from(parent.context) return BreedsViewHolder(inflater.inflate(R.layout.item_breed, parent, false)) } override fun onBindViewHolder(holder: BreedsViewHolder, position: Int) { val breed = getItem(position) holder.breed.text = breed!!.name } } Como utilizar? Adapter BreedsAdapter.kt -
class BreedsAdapter() : PagingDataAdapter<Breed, BreedsAdapter.BreedsViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): BreedsViewHolder { val inflater = LayoutInflater.from(parent.context) return BreedsViewHolder(inflater.inflate(R.layout.item_breed, parent, false)) } override fun onBindViewHolder(holder: BreedsViewHolder, position: Int) { val breed = getItem(position) holder.breed.text = breed!!.name } } Como utilizar? Adapter BreedsAdapter.kt -
object Singleton { } Singleton ☝ public class Singleton {
private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } } -
interface Kennel { fun getDog(name: String) } val kennel =
object : Kennel { override fun getDog(name: String) {...} } SAM (Single Abstract Method) -
interface Kennel { fun getDog(name: String) } val kennel =
object : Kennel { override fun getDog(name: String) {...} } val kennel = Kennel { name -> ...} SAM (Single Abstract Method) -
class ClassWithAHugeNameThatDoestReallyMatter typealias ShortName = ClassWithAHugeNameThatDoestReallyMatter typealias Dogs = List<Dog>
val dogs: Dogs = mutableListOf() TypeAlias -
Aplicar uma máscara sobre uma view ⚪ <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/colorPrimary" /> <corners android:topRightRadius="25dp" android:topLeftRadius="25dp" android:bottomRightRadius="25dp" android:bottomLeftRadius="25dp"/> </shape> -
Aplicar uma máscara sobre uma view ⚪ <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" /> -
Dividir o ecrã Para ativar: 1. Botão direito sobre a
tab que queremos dividir 2. “Split Vertically” -
Android Studio ⌨ Mover linhas de código - Bloco ctrl
shift + ⬆ + https://developer.android.com/studio/intro/keyboard-shortcuts ⬇ -
Android Studio ⌨ Mover linhas de código - Bloco cmd
shift + ⬆ + https://developer.android.com/studio/intro/keyboard-shortcuts ⬇ -
Android Studio ⌨ Mover linhas de código - Bloco cmd
shift + ⬆ + https://developer.android.com/studio/intro/keyboard-shortcuts ⬇ -
Android Studio ⌨ Mover linhas de código - Bloco cmd
shift + ⬆ + https://developer.android.com/studio/intro/keyboard-shortcuts ⬇ -
Trabalho para casa • Implementar a vista de detalhes para
um cão ◦ Nome ◦ Imagem ◦ Detalhes -
Trabalho para casa • Carregar num dos itens da RecyclerView
◦ Abre a vista de detalhes para aquele cão -
Android Training Program PORTUGAL Aula #6 Jetpack, jetpack, jetpack Próxima
aula: 25 de Novembro