3.2 - Exemple complet
Una vegada hem vist les classes que ens fan falta per a accedir per mig de ROOM, anem a fer les modificacions oportunes a l'exemple CoffeeShops_Fragments.
Recordem que aquest exemple mostra en un primer fragment (FirstFragment) una sèrie de cafeteries (amb una imatge, nom, adreça i puntuació). En punxar en una cafeteria, anem un segon fragment (SecondFragment) on es veuen el comentaris que s'han fet a aquesta cafeteria. Haurem de modificar, per tant, aquestos fitxers, així com adaptar CoffeeAdapter i alguna cosa més.
- Copieu-vos el projecte CoffeeShops_Fragments en un altre projecte anomenat CoffeeShops_Fragments_ROOM, per a poder conservar l'original.
- Modifiqueu el nom del projecte, nom del paquet, nom de l'aplicació, ... Ho farem amb 2 accions:
- Des del menú Edit -> Find -> Repalce in path... (si no està aquesta opció, doncs Edit -> Find -> Repalce in Files...) canvieu CoffeeShops_Fragments per CoffeeShops_Fragments_ROOM. Aneu amb compte vigilant que la diferenciació de majúscules i minúscules estiga activada (ha d'estar en blau). Es diu Match case, i és un simbolet així: Aa
- Feu el mateix amb per a canviar coffesShops_fragments en coffesShops_fragments_room (en minúscules), cuidant que la diferenciació entre majúscules i minúscules continue activa.
- Sobre app -> java -> com.example.coffeeshops_fragments fer un Refactor -> Rename a coffeeshops_fragments_room i triar després l'opció Rename package. Això hauria d'actualitzar el paquet en totes les classes definides, i també en el AndroidManifest.xml
- Executeu-lo per veure que continua funcionant, ara ja amb el nou nom
- Modifiqueu el build.gradle de l'aplicació per a que continga la llibreria Room, afegint les línies següents i després sincronitzant:
plugins {
...
id 'kotlin-kapt'
}
dependencies {
...
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
}
- Copieu les classes de l'apartat anterior: Coffee, Comment, CoffeeWithComments, CoffeeShopsDao i CoffeeShopsDatabase. Recordeu que Coffee i Comment substituiran a les anteriors
- Ara és el moment de modificar els programes fets en el mòdul de DI, pera a adaptar-lo a l'accés a la Base de Dades a través de Room. Anirem mirant cadascun d'ells
-
CoffeeAdapter
Igual que vam fer en el punt 2.2.1, ara no agafem les imatges del res, sinó que ens arriba la mateixa imatge. També aprofitem per a mostrar la puntuació de la Base de Dades. Posem tota la funció bindCards:
fun bindCards(t: Coffee, onClick: (View) -> Unit) {
//image.setImageResource(t.image)
val img = t.image
if (img != null) {
val imgBmp = BitmapFactory.decodeByteArray(img, 0, img.size)
image.setImageBitmap(imgBmp)
}
text.text = t.title
text1.text = t.subtitle
if (t.points!=null)
barstars.rating = t.points.toFloat()
barstars.onRatingBarChangeListener = RatingBar.OnRatingBarChangeListener { ratingBar: RatingBar, fl: Float, b: Boolean ->
points.text = fl.toString()
}
itemView.setOnClickListener{ onClick(itemView) }
} -
CommentsAdapter
No cal modificar res en aquest. Només en tot cas arreglar que la propietat de Comment es diu comm, no comm1
-
FirstFragment
En aquest sí que tenim feina. Per una banda hem d'agafar les dades de la Base de Dades a través de Room. Per una altra banda hem de passar la informació correcta al SecondFragment
Per a la primera qüestió, recordeu que no podem accedir des del Thread principal, per tant ens muntem un altre per a fer tot l'accés a Room
Per a la segona qüestió, voldrem passar al SecondFragment no únicament el nom del cafè, sinó tots els comentaris també. Aleshores passarem un objecte CoffeWithComments, perquè ahí està tot. Per a poder passar-lo en el bundle, ha d'heretar de Serializable.
També aprofitarem per a inicialitzar la puntuació de les cafeteries, ja que tenim guardada en la Base de Dades aquesta puntuació.
Ací teniu tot el FirstFragmentimport android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.room.Room
/**
* A simple [Fragment] subclass as the default destination in the navigation.
*/
class FirstFragment : Fragment() {
private var items: ArrayList<Coffee> = ArrayList()
private var itemsWithComments: ArrayList<CoffeeWithComments> = ArrayList()
private var roomThread: Thread = object : Thread() {
override fun run() {
val db = Room.databaseBuilder(
context!!,
CoffeeShopsDatabase::class.java, "CoffeeShops_Com.sqlite"
).createFromAsset("CoffeeShops_Com.sqlite").build()
items = ArrayList(db.coffeeshopsDao().getCoffees())
itemsWithComments = ArrayList(db.coffeeshopsDao().getCoffeesWithComments())
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_first, container, false)
if (items.size==0) { // per a no executar-lo una altra vegada quan tornem del SecondFragment
roomThread.start()
roomThread.join()
}
val recView: RecyclerView = root.findViewById(R.id.recView)
recView.setHasFixedSize(true)
val adaptador = CoffeeAdapter(items)
recView.adapter = adaptador
recView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
adaptador.onClick = {
val c = itemsWithComments[recView.getChildAdapterPosition(it)]
val bundle = bundleOf("coffee" to c)
findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment, bundle)
}
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
} -
SecondFragment
Només haurem d'agafar la informació que ens arriba del bundle, tenint en compte que és un objecte CoffeeWithComments. Ara ja no inicialitzem els comentaris de forma directa sinó que els agafem de l'anterior.
Ací teniu tot el SecondFragmentimport android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
/**
* A simple [Fragment] subclass as the second destination in the navigation.
*/
class SecondFragment : Fragment() {
private lateinit var Comments: ArrayList<Comment>
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val root = inflater.inflate(R.layout.fragment_second, container, false)
val texto: TextView = root.findViewById(R.id.textview_second)
val coffee = arguments?.get("coffee") as CoffeeWithComments
texto.text = coffee.coffee.title
Comments=ArrayList(coffee.coms)
val recView: RecyclerView = root.findViewById(R.id.recyclerview_coment)
recView.setHasFixedSize(true)
val adaptador = CommentsAdapter(Comments)
recView.adapter = adaptador
recView.layoutManager = GridLayoutManager(context, 2)
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
/* view.findViewById<Button>(R.id.button_second).setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}*/
}
} - Creeu-vos la carpeta de assets des del menú: File -> New -> Folder -> Assets Folder, i copieu en ella la Base de Dades CoffeeShops_Com.sqlite
-
Llicenciat sota la Llicència Creative Commons Reconeixement NoComercial CompartirIgual 2.5