Exemple d'inversió de dependències amb el Recycler view senzill¶
Problema de callbacks:¶
Si examinem l'exemple de recyclerview tal i com està, (passant funcions de callback), podem trobar els problemes següents:
1. Memory Leaks¶
- La lambda fà referència a l'activity( el this en el Toast)
- Si l'Activity es destrueix (rotació, backstack), però l'Adapter/ViewHolder segueix viu → leak.
- L'Activity no es pot recollir per garbage collector.
2. Acoblament fort¶
- L'Activity s'ha de conèixer què fa l'Adapter (passar callbacks específics).
- Difícil reutilitzar l'Adapter en un altre context.
3. Violació Single Responsibility¶
- L'Activity fa 3 coses:
- Presenta UI
- Gestiona RecyclerView
- Gestiona negocis (què fer al clic). Aixó últim no ho hauria de fer. No és la serva responsabilitat.
Sol·lució amb inversió de dependències (Dependency Inversion Principle - DIP)¶
1. Interfície clara i tipada¶
interface ItemClickListener {
fun onItemClick(item: MyItem)
}
2. Adapter rep interfície (NO lambda)¶
class MyAdapter(
private val items: List<MyItem>,
private val listener: ItemClickListener // ← Millor!
) : RecyclerView.Adapter<MyViewHolder>() {
// ... mateix codi
}
3. Activity només implementa interfície¶
class MainActivity : AppCompatActivity(), ItemClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
adapter = MyAdapter(items, this) // ← Passa Activity com a listener
recyclerView.adapter = adapter
}
// Lògica de negoci AQUÍ, separada de UI
override fun onItemClick(item: MyItem) {
Toast.makeText(this, "Clicat ${item.title}", Toast.LENGTH_SHORT).show()
// O millor: cridar ViewModel
// viewModel.onItemSelected(item)
}
}
Què diu el principi DIP?¶
"Les mòduls d'alt nivell NO han de dependre de mòduls de baix nivell.
AMBDOs han de dependre d'abstraccions (interfícies)."
En el nostre cas:¶
- Incorrecte: Activity (alt nivell) ← DEPEN de MyAdapter (baix nivell)
- Correcte: Activity (alt nivell) → ItemClickListener ← MyAdapter (baix nivell)
- L'Activity es pot canviar (Fragment, Compose Screen) sense tocar Adapter
- L'Adapter es pot reutilitzar en qualsevol Activity/Fragment
- No té memory leaks (no captura 'this' directament dins lambda)
- Testejable: mockejar ItemClickListener