¿Qué es un Bundle?
Un Bundle es un contenedor de pares clave-valor que Android usa para pasar datos entre componentes: entre Activities (como viste con los Extras), entre Fragments, y para guardar estado en el ciclo de vida.
Para pasar datos a un Fragment al crearlo, usás Fragment.arguments: una propiedad Bundle que Android preserva a través de recreaciones del Fragment.
El patrón newInstance()
La forma clásica de pasar argumentos a un Fragment es un factory method estático en el companion object:
class DetalleFragment : Fragment(R.layout.fragment_detalle) {
companion object {
private const val ARG_PRODUCTO_ID = "producto_id"
private const val ARG_NOMBRE = "nombre"
// Factory method: así se crea el Fragment con sus datos
fun newInstance(productoId: Int, nombre: String): DetalleFragment {
return DetalleFragment().apply {
arguments = Bundle().apply {
putInt(ARG_PRODUCTO_ID, productoId)
putString(ARG_NOMBRE, nombre)
}
}
}
}
}
Y así lo instanciás desde otro Fragment o la Activity:
// Desde el llamador:
val detalle = DetalleFragment.newInstance(productoId = 42, nombre = "Tablet")
supportFragmentManager.commit {
replace(R.id.container, detalle)
addToBackStack(null)
}
¿Por qué no pasar datos por el constructor?Android puede recrear el Fragment en cualquier momento (rotación, restauración de estado) llamando al constructor vacío. Si pasaste datos por el constructor, se pierden. Los arguments Bundle sobreviven a la recreación porque Android los serializa automáticamente.
Recibir y usar los argumentos
class DetalleFragment : Fragment(R.layout.fragment_detalle) {
// Lectura segura con el operador requireArguments()
private val productoId: Int by lazy {
requireArguments().getInt(ARG_PRODUCTO_ID)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// También podés leerlos directamente:
val nombre = arguments?.getString(ARG_NOMBRE) ?: "Sin nombre"
binding.tvNombre.text = nombre
// Cargar datos usando el ID
viewModel.cargarProducto(productoId)
}
}
Safe Args — la forma moderna y segura
Con Navigation Component (lección 03), podés usar el plugin Safe Args, que genera código tipado para pasar argumentos entre destinos. Elimina por completo las claves String y los casts manuales.
Configuración en build.gradle:
// build.gradle (project)
plugins {
id("androidx.navigation.safeargs.kotlin") version "2.7.7" apply false
}
// build.gradle (app)
plugins {
id("androidx.navigation.safeargs.kotlin")
}
Definís los argumentos en el NavGraph:
<!-- nav_graph.xml -->
<fragment
android:id="@+id/detalleFragment"
android:name="ar.pensa.app.DetalleFragment">
<argument
android:name="productoId"
app:argType="integer" />
<argument
android:name="nombre"
app:argType="string" />
</fragment>
Safe Args genera automáticamente una clase DetalleFragmentArgs. Usarla es limpio y type-safe:
// Navegar enviando argumentos (desde el Fragment origen):
val accion = HomeFragmentDirections.actionHomeToDetalle(
productoId = 42,
nombre = "Tablet"
)
findNavController().navigate(accion)
// Recibir en DetalleFragment:
class DetalleFragment : Fragment(R.layout.fragment_detalle) {
private val args: DetalleFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val id = args.productoId // Int, type-safe
val nombre = args.nombre // String, type-safe
}
}
Safe Args vs Bundle manualUsá Safe Args siempre que uses Navigation Component. Para casos sin Navigation (Fragment en Activity directamente), el patrón newInstance() con Bundle sigue siendo la opción correcta.
Pasar objetos con @Parcelize
Para pasar objetos de tus propias clases en un Bundle, implementá Parcelable. El plugin kotlin-parcelize lo hace trivial:
// En build.gradle (app):
plugins {
id("kotlin-parcelize")
}
// Tu data class:
@Parcelize
data class Producto(
val id: Int,
val nombre: String,
val precio: Double
) : Parcelable
// Pasándolo en un Bundle:
arguments = Bundle().apply {
putParcelable("PRODUCTO", producto)
}
// Recibiéndolo:
val producto = arguments?.getParcelable("PRODUCTO", Producto::class.java)
Limitación importanteLos Bundles tienen un límite de tamaño (~1MB en total). No los uses para pasar listas grandes o imágenes. Para esos casos, guardá el dato en el ViewModel y pasá solo un ID como argumento.