30

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().

botflot
  • 275
  • 1
  • 4
  • 9

3 Answers3

75

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[]"

LaVepe
  • 1,137
  • 1
  • 8
  • 12
  • 2
    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](https://developer.android.com/topic/libraries/architecture/navigation/navigation-pass-data) – Yuan Fu Jan 29 '19 at 01:01
  • 3
    @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](https://medium.com/@vepetruskova/using-safe-args-plugin-current-state-of-affairs-41b1f01e7de8) about safe args and I update it when there are new releases, maybe you'd find it useful – LaVepe Jan 29 '19 at 09:01
  • 1
    @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!> – wesley franks Dec 19 '19 at 21:52
  • 5
    @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 Dec 20 '19 at 10:12
  • This should be the approved/accepted answer and the one that was accepted can cause issues as `@Parcelize` will not work and the data will not be stored in the state. – rewgoes Oct 29 '20 at 03:34
24

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.

rewgoes
  • 656
  • 2
  • 9
  • 23
Alex
  • 9,102
  • 3
  • 31
  • 35
  • 3
    Passing arrays of Parcelables is now possible by adding `[]` after the type you want to use, for example: `` – KubaK Sep 14 '20 at 14:57
  • 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 – rewgoes Oct 29 '20 at 03:08
22

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().

kkaun
  • 603
  • 7
  • 19
  • @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. – kkaun Dec 20 '19 at 10:16