Safe Args: use list of parcelables

18,355

Solution 1

Currently i don't think there is a simple way to use list of parcelables with safe args, But i have found some "hack" to make this work. For example, i have object 'User' and it parcelable, i am declaring a new parcelable object 'Users' that extending ArrayList().

@Parcelize
data class User(var name: String, val age: Int): Parcelable

@Parcelize
class Users: ArrayList<User>(), Parcelable

Now i can set 'Users' as argument in navigation

<argument
      android:name="users"
      app:argType="com.navigation.test.Users"/>

And passing array list of parcelables between destinations:

 val user=User("Alex", 36)
 val users= Users()
 users.add(user)
 val action=MainFragmentDirections.actionMainFragmentToSecondFragment(users)
 NavHostFragment.findNavController(this@MainFragment).navigate(action)

And to retrieve them on other destination:

val users=SecondFragmentArgs.fromBundle(arguments).users
val user=users[0]
txtViewName.text=user.name
txtViewAge.text="${user.age}"

Update:

Support to list of objects coming in alpha8: https://issuetracker.google.com/issues/111487504


Update 2: The approach mentioned above will not work in case the activity is recreated, as @Parcelize will not be able to store/restore the list.

The object will be store in the state bundle, however, it will store an empty list of objects.

Solution 2

Yes, since version 1.0.0-alpha08 you can now pass arrays of parcelable objects like this:

<argument
  android:name="users"
  app:argType="com.navigation.test.User[]"/>

For passing arrays of primitive types use for e.g. app:argType="integer[]"

Solution 3

An improvement to @LaVepe suggestion: as for Android Studio 3.4.2 you can pass Parcelable array with in-built feature of navigation editor by specifying Arguments for chosen destination. Just check 'Array' option after choosing your custom Parcelable class which should not be wrapped in any collection beforehand:

Example

EDIT Here how it looks in xml:

<argument
        android:name="items"
        app:argType="com.company.domain.Item[]" />

In your Fragment/Activity code you might strictly pass a typed array of model Parcelable items. If you have non-array collection and write in Kotlin, it may be achieved with (if you have list beforehand) list.toTypedArray().

Share:
18,355

Related videos on Youtube

botflot
Author by

botflot

Updated on September 15, 2022

Comments

  • botflot
    botflot over 1 year

    I am using the Safe Args plugin with the new Navigation components for my Android project. Now I have an argument that is an array list of parcelables, is there a way to use this with the Safe Args Plugin?

    Something like app:argType=ParcelableArray. This should be possible since there are bundle methods like putParcelableArrayList().

  • Yuan Fu
    Yuan Fu over 5 years
    Thanks. It works. Why google didn't write this done in their documents pages. So confused that every time I want something. I have to "Google" it instead of checking their useless "documentations" pages to find out. navigation-pass-data
  • LaVepe
    LaVepe over 5 years
    @YuanFu Well it's still just alpha release, there can be a lot of changes until this plugin becomes stable. I have made an article about safe args and I update it when there are new releases, maybe you'd find it useful
  • wesley franks
    wesley franks over 4 years
    @LaVepe thanks for your comment and the article. I took a look at it. I'm having an error setting my array in the action details. .setList(list) <- error = Array<(out) Object!>
  • kkaun
    kkaun over 4 years
    @wesleyfranks it seems that you're trying to set list instead of Parcelable Array so the typing is failing. If you're using Kotlin, you can try convert your list with list.toTypedArray() method.
  • kkaun
    kkaun over 4 years
    @wesleyfranks edited post. If I right understand your problem mentioned in your another comment, you should really look into type fixing in Java/Kotlin code.
  • KubaK
    KubaK over 3 years
    Passing arrays of Parcelables is now possible by adding [] after the type you want to use, for example: <argument android:name="users" app:argType="com.example.User[]" />
  • rewgoes
    rewgoes over 3 years
    It works to pass the data/list but it does not keep the state, as it will not Parcelize the list for you. This can introduce some bugs in case the process is killed and restored in the destination that receives the argument. The state bundle will have a reference to the object passed as an argument, but the list will be empty. It will also happen in case you use the Users class with SavedStateHandle inside a ViewModel. The list will be null as that data will not be saved. @Alex