Android Training Program - Portugal, Aula 5

9e9eb825c69d719f2d3c32bdd3bc971e?s=47 ATP Portugal
November 18, 2020

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

9e9eb825c69d719f2d3c32bdd3bc971e?s=128

ATP Portugal

November 18, 2020
Tweet

Transcript

  1. Android Training Program PORTUGAL Aula #5 Listas, listas e mais

    listas
  2. ? 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
  3. Andres-Leonardo Martinez-Ortiz Google Carlos Mota Formador Renato Almeida Formador @davilagrau

    @cafonsomota @tallnato Equipa Daniela Ferreira Gestora de comunidades
  4. ? 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
  5. #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 ?
  6. Sumário Photo by Mika Baumeister on Unsplash ? Resumo da

    aula anterior ? RecyclerView ? Retrofit ? Glide ? Paging ? Kotlin para principiantes ? Sexta-Feira negra
  7. http://events.withgoogle.com/atp2020 ? atp-suporte@googlegroups.com http://bit.ly/atp2020-youtube http://bit.ly/atp2020-discord Links

  8. http://bit.ly/atp2020-live

  9. http://bit.ly/atp2020-codelabs

  10. http://bit.ly/kahoot-aula5

  11. Resumo da Aula #4

  12. LiveData ViewModel Room

  13. ? 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
  14. None
  15. ? 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 ...
  16. atualizar atualizar atualizar atualizar desenha o ecr? desenha o ecr?

    desenha o ecr? objetivo: 60fps UI-thread Opera??es assíncronas
  17. ? 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
  18. ? Service ? Threads ? IntentService ? AsyncTasks ? WorkManager

    ? JobScheduler ? DownloadManager ? AlarmManager ? Coroutines Opera??es assíncronas Solu??es
  19. 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
  20. 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
  21. Aula #5

  22. RecyclerView

  23. ? é 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
  24. RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter

    ViewHolder data Adapter ViewHolder data
  25. RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter

    ViewHolder data Adapter ViewHolder data
  26. dependencies { ... implementation "androidx.recyclerview:recyclerview:1.1.0" } Como utilizar? Importar a

    biblioteca app/build.gradle
  27. class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } } Como utilizar? Criar uma Activity/Fragment MainActivity.kt
  28. 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
  29. <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_feed" android:layout_width="match_parent" android:layout_height="wrap_content" /> Como utilizar? Definir a RecyclerView

    no layout... res/layout/activity_main.xml
  30. <?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
  31. <?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
  32. RecyclerView RecyclerView LayoutManager Adapter ViewHolder data Activity RecyclerView LayoutManager Adapter

    ViewHolder data Adapter ViewHolder data
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. RecyclerView Activity RecyclerView LayoutManager Adapter ViewHolder data RecyclerView LayoutManager Adapter

    ViewHolder data Adapter ViewHolder data
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. MainActivity.kt

  47. Retrofit

  48. ? 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
  49. O Retrofit transforma uma API HTTP numa interface

  50. The Dog API

  51. The Dog API

  52. The Dog API interface DogApiClient { @GET("breeds") fun getBreeds() :

    List<Dog> }
  53. The Dog API interface DogApiClient { @GET("breeds") fun getBreeds() :

    List<Dog> }
  54. 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 )
  55. Resultado da API "height": { "imperial": "9 - 11.5", "metric":

    "23 - 29" } data class Height ( val imperial : String, val metric : String )
  56. Resultado da API "weight": { "imperial": "6 - 13", "metric":

    "3 - 6" } data class Weight ( val imperial : String, val metric : String )
  57. 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 )
  58. 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 )
  59. ? Biblioteca de convers?o de JSON para Kotlin e Java

    ? Optimizada para Android ? Compatível Retrofit Moshi
  60. 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
  61. 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
  62. interface DogApiClient { @GET("breeds") fun getBreeds() : Call<List<Dog>> } Como

    utilizar? A interface DogApiClient.kt
  63. interface DogApiClient { @GET("breeds") fun getBreeds() : Call<List<Dog>> } Como

    utilizar? A interface DogApiClient.kt Permite realizar trabalho em background
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. Glide

  74. ? 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
  75. ? 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
  76. ? Permitir uma transi??o suave e rápido em qualquer tipo

    de lista de imagens ? Eficiente a carregar, redimensionar e descarregar imagens facilmente Objetivos
  77. Exemplo Glide.with(activity) .load("https://placedog.net/500") .into(imageView)

  78. Exemplo GIF Glide.with(activity) .load("https://media.giphy.com/media/xTiTnf9SCIVk8HIvE4/giphy.gif") .into(imageView)

  79. Placeholder Glide.with(activity) .load("https://placedog.net/500") .placeholder(R.drawable.ic_camera) .into(imageView)

  80. Error Glide.with(activity) .load("url_que_n?o_tem_imagem") .error(R.drawable.ic_error) .into(imageView)

  81. Transforma??es Glide.with(activity) .load("https://placedog.net/500") .transform(CircleCrop()) .into(imageView)

  82. Transforma??es Glide.with(activity) .load("https://placedog.net/500") .centerCrop() .into(imageView)

  83. Cache Glide.with(activity) .load("https://placedog.net/500") .diskCacheStrategy(DiskCacheStrategy.ALL) .into(imageView)

  84. ? 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
  85. dependencies { ... implementation "com.github.bumptech.glide:glide:4.11.0" } Como utilizar? Importar a

    biblioteca app/build.gradle
  86. // 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)
  87. Paging

  88. ? 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
  89. Paging 3 Repository PagingSource RemoteMediator ViewModel Pager PagingDataAdapter Flow<PagingData>

  90. dependencies { ... implementation "androidx.paging:paging-runtime:3.0.0-alpha03" } Como utilizar? Importar a

    biblioteca app/build.gradle
  91. 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
  92. 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
  93. 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
  94. class ListViewModel: ViewModel() { private val repository = Repository() val

    breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt
  95. class ListViewModel: ViewModel() { private val repository = Repository() val

    breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt
  96. class ListViewModel: ViewModel() { private val repository = Repository() val

    breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt
  97. class ListViewModel: ViewModel() { private val repository = Repository() val

    breedsListByPage = Pager(PagingConfig(pageSize = 20), pagingSourceFactory = { DogPagingSource(repository) }).flow } Como utilizar? ViewModel ListViewModel.kt
  98. 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
  99. 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
  100. 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
  101. 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
  102. 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
  103. 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
  104. 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
  105. 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
  106. Passaporte para a Google

  107. Abre o Android Studio e vamos come?ar a programar ??

  108. VS Ronda 4

  109. object Singleton { } Singleton ? public class Singleton {

    private static Singleton instance; private Singleton(){} public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
  110. interface Kennel { fun getDog(name: String) } val kennel =

    object : Kennel { override fun getDog(name: String) {...} } SAM (Single Abstract Method)
  111. interface Kennel { fun getDog(name: String) } val kennel =

    object : Kennel { override fun getDog(name: String) {...} } val kennel = Kennel { name -> ...} SAM (Single Abstract Method)
  112. class ClassWithAHugeNameThatDoestReallyMatter typealias ShortName = ClassWithAHugeNameThatDoestReallyMatter typealias Dogs = List<Dog>

    val dogs: Dogs = mutableListOf() TypeAlias
  113. Sexta-Feira negra Photo by Xiaolong Wong on Unsplash

  114. 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>
  115. 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" />
  116. Dividir o ecr? Para ativar: 1. Bot?o direito sobre a

    tab que queremos dividir 2. “Split Vertically”
  117. Android Studio ? Mover linhas de código - Bloco ctrl

    shift + ? + https://developer.android.com/studio/intro/keyboard-shortcuts ?
  118. Android Studio ? Mover linhas de código - Bloco cmd

    shift + ? + https://developer.android.com/studio/intro/keyboard-shortcuts ?
  119. Android Studio ? Mover linhas de código - Bloco cmd

    shift + ? + https://developer.android.com/studio/intro/keyboard-shortcuts ?
  120. Android Studio ? Mover linhas de código - Bloco cmd

    shift + ? + https://developer.android.com/studio/intro/keyboard-shortcuts ?
  121. Trabalho Para Casa ??

  122. Trabalho para casa ? Implementar a vista de detalhes para

    um c?o ? Nome ? Imagem ? Detalhes
  123. Trabalho para casa ? Carregar num dos itens da RecyclerView

    ? Abre a vista de detalhes para aquele c?o
  124. Dúvidas?

  125. Continuamos a responder no discord

  126. Obrigado ?♀

  127. Android Training Program PORTUGAL Aula #6 Jetpack, jetpack, jetpack Próxima

    aula: 25 de Novembro
97精品免费公开在线视频_ caoporn国产免费_ 超碰高清熟女一区二区