grandstaish/paperparcel

Transient not working

jporcelli-tt opened this issue · 13 comments

@PaperParcel
data class UIModel constructor(
        val id: String,
        val isGetting: Boolean = false,
        val pk: String? = null,
        @Transient val listData: List<Data>? = null,
        val taxonym: String? = null
) : PaperParcelable {
    constructor(
            id: String,
            isGetting: Boolean,
            pk: String?,
            taxonym: String?
    ) : this(
            id,
            isGetting,
            pk,
            null,
            taxonym
    )

    companion object {
        @JvmField
        val CREATOR = PaperParcelUIModel.CREATOR
    }
}

So first off I had to add in this secondary constructor in order to get this to build. The Data class is annotated @PaperParcel and implements PaperParcelable with the CREATOR companion object. Everything is in Kotlin. This was the only way I could get a successful build. There is a generated file, PaperParcelUIModel which has a writeToParcel method which correctly excludes the Transient field and a createFromParcel method which calls the secondary constructor. However when I, run, observe, and debug, my code I see that the Transient field with the List is still being included in the Bundle used to save and restore state. Any idea on why this is? Thanks, James.

I was on 2.0.1 btw

Will it compile if you add @JvmOverloads to the primary constructor and delete the secondary one? I think the issue is that PaperParcel needs a constructor accessible by Java which doesn't include your transient property

As for your other question, I'm not sure how anything could be included in the Bundle without being written in the generated class

I tried adding @jvmoverloads because I saw that in another issue but it didnt work for me. Would not build an the error is something along the lines of cannot find public setter or constructor to use for private fields. I can get you the exact message if it helps.

Yes this is very bizarre ugh.. This the code to save and restore

  override fun save() =
            super.save().apply {
                putParcelable(BUNDLE_UI_MODEL, uiModel)
            }
    override fun restore(savedState: Bundle) {
        super.restore(savedState)
        savedState.getParcelable<UIModel>(BUNDLE_UI_MODEL)?.let { uiModel = it }
    }
@PaperParcel
data class UIModel @JvmOverloads constructor(
        val id: String,
        val isGetting: Boolean = false,
        val pk: String? = null,
        @Transient val listData: List<Data>? = null,
        val taxonym: String? = null
) : PaperParcelable {

    companion object {
        @JvmField
        val CREATOR = PaperParcelUIModel.CREATOR
    }
}

error: Field .UIModel.taxonym is private and PaperParcel cannot find a constructor parameter or setter method for it (using constructor UIModel(java.lang.String,java.lang.String,java.lang.String,boolean,boolean,java.lang.String)). PaperParcel will search for setter methods and constructor parameters using the conventions defined at http://grandstaish.github.io/paperparcel/#model-conventions
private final java.lang.String taxonym = null;

If this field should be excluded by PaperParcel then you can do this by:

  • Adding the static modifier
  • Adding the transient modifier

Note: exclude rules can be customized using the @PaperParcel.Options API.

I have modified the code I posted because I dont want to post the exact code but problem should be all the same

I moved the field annotated Transient to be the last parameter in the constructor and the above now builds. The generated class has a constructor minus the last field which is annotated Transient. The field is still included in the saved state bundle though. If you think of anything let me know. I removed a few fields and renamed them to obscure the exact code but I can post the exact code with just the names changed if you think that will help. Or if any other information will help let me know. Thanks

Oh right, @JvmOverloads doesn't generate every possible combination of constructors for you, just a subset. I think you'll also need the transient property to be the last property in the constructor for it to generate the 4-arg constructor you need.

Your code to save and restore looks fine to me

cool yea thats working now. Field is still included in the saved state bundle though. (Just wanted to clarify that for anybody else)

How are you determining that the field is persisted?

by manual testing and debugging and inspecting the saved state bundle contents. Manual testing and observations showed the list was being restored on orientation change because it was rendered immediately. Then I confirmed by debugging and observed the saved state bundle indeed had the UIModel parseled inside and included the same full List field that was in the model before orientation change

Configuration changes won't test parcelling as no reading and writing occurs (you can test this by adding a breakpoint). Android optimises this case because there's no need to waste time writing bytes only to read them again straight away. To test parcelling/unparcelling correctly, you'll need to kill your app process and start the app again. There's a "Terminate Application" button that you can use in Android Studio for this purpose. Background your app, then kill it, then restart it.

That makes sense. Looks like everything is working now then so feel free to close this issue. Thanks for the help!