Crash in RadDataFormInstanceState on onSaveInstanceState

7 posts, 0 answers
  1. Sacha
    Sacha avatar
    10 posts
    Member since:
    Sep 2015

    Posted 08 Jun Link to this post

    Hi,

    I have noticed that if you annotate a field with skip = true, then when onSaveInstanceState is called, there is a crash. The problem is this:

    If skip = true, then the property is not added to the list of properties in DataFormEntityAdapter.generateProperties

    if(!property.getSkip()) {
        this.properties.add(property);
    }

    But, in RadDataFormInstanceState constructor, it iterates over all properties (whether they have been skipped or not), and tries to find an editor. This will fail and dataForm.getExistingEditorForProperty(property.name()) will return null, so when getEditorView is called on the null return value, it crashes.

    public RadDataFormInstanceState(Parcelable superState, RadDataForm dataForm) {
        super(superState);
        this.editorIds = new HashMap();
        Iterator i$ = dataForm.getEntity().properties().iterator();
     
        while(i$.hasNext()) {
            EntityProperty property = (EntityProperty)i$.next();
            this.editorIds.put(property.name(), Integer.valueOf(dataForm.getExistingEditorForProperty(property.name()).getEditorView().getId()));
        }
     
    }

    It would be great if you could provide a fix, but in the meantime it would be totally awesome if you could suggest a workaround. Basically, I don't want all the fields in an annotated class to be shown in the DataForm - I want to hide some of them.

    Many thanks

    Sacha

  2. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 13 Jun Link to this post

    Hello Sacha,

    Thanks for reporting this. I have fixed it in our development branch.
    The fix will be available in our next release.
    Currently you can work around it simply by inheriting from RadDataForm and overriding the onSaveInstanceState() and onRestoreInstanceState(). Also the RadDataFormInstanceState class is public so you can override its methods as well.

    Regards,
    Victor
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. DevCraft banner
  4. Sacha
    Sacha avatar
    10 posts
    Member since:
    Sep 2015

    Posted 13 Jun in reply to Victor Link to this post

    Thanks Victor. I looked at inheriting from RadDataForm and overriding onSaveInstanceState, but the problem is that RadDataForm calls super.onSaveInstanceState. So in my inherited data form, I would need to do something like the code below. 

    But I can't call super.super in Java.

    Any suggestions?

     

    protected Parcelable onSaveInstanceState() {
        return new RadDataFormInstanceStateWithTheFix(super.super.onSaveInstanceState(), this);
    }

  5. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 13 Jun Link to this post

    Ah yes, my bad.
    In this case you will have to completely overwrite the RadDataFormInstanceState class. For example:
    @Override
        protected Parcelable onSaveInstanceState() {
            return new CustomRadDataFormInstanceState(super.onSaveInstanceState(), this);
        }
     
        @Override
        protected void onRestoreInstanceState(Parcelable state) {
            CustomRadDataFormInstanceState dataFormState = (CustomRadDataFormInstanceState)state;
     
            for(EntityProperty property : this.entity.properties()) {
                if(property.getSkip()) {
                    continue;
                }
                getExistingEditorForProperty(property.name()).getEditorView().setId(dataFormState.editorIds.get(property.name()));
            }
     
            super.onRestoreInstanceState(dataFormState.getSuperState());
        }

    And the state class itself:
    public class CustomRadDataFormInstanceState extends View.BaseSavedState {
            public static final Parcelable.Creator<CustomRadDataFormInstanceState> CREATOR = new Parcelable.Creator<CustomRadDataFormInstanceState>() {
                @Override
                public CustomRadDataFormInstanceState createFromParcel(Parcel source) {
                    return new CustomRadDataFormInstanceState(source);
                }
     
                @Override
                public CustomRadDataFormInstanceState[] newArray(int size) {
                    return new CustomRadDataFormInstanceState[size];
                }
            };
     
            public HashMap<String, Integer> editorIds = new HashMap<>();
     
            public CustomRadDataFormInstanceState(Parcelable superState) {
                this(superState, null);
            }
     
            public CustomRadDataFormInstanceState(Parcelable superState, RadDataForm dataForm) {
                super(superState);
     
                for(EntityProperty property : dataForm.getEntity().properties()) {
                    if(property.getSkip()) {
                        continue;
                    }
     
                    editorIds.put(property.name(), dataForm.getExistingEditorForProperty(property.name()).getEditorView().getId());
                }
            }
     
            public CustomRadDataFormInstanceState(Parcel superState) {
                super(superState);
            }
     
            @Override
            public void writeToParcel(@NonNull Parcel dest, int flags) {
                super.writeToParcel(dest, flags);
     
                dest.writeMap(editorIds);
            }
        }

    Please write again if you need further assistance.

    Regards,
    Victor
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  6. Sacha
    Sacha avatar
    10 posts
    Member since:
    Sep 2015

    Posted 13 Jun in reply to Victor Link to this post

    Hi Victor,

    Will that work? Because when the following call is made, it will call super.onSaveInstanceState, which will then call RadDataFormInstanceState, not CustomRadDataFormInstanceState:

    protected Parcelable onSaveInstanceState() {
        return new CustomRadDataFormInstanceState(super.onSaveInstanceState(), this);
    }

  7. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 13 Jun Link to this post

    Hi Sacha,

    Yes you are correct. There appears to be no way to avoid the base instance state object.
    I suggest modifying the controls source in this case. As a customer you should have access to source of the controls. You can modify it with this change and create your own custom build that you can use in your app.

    If you are reluctant to modify the source I can send you a private development build with the fix. This second option however may expose your app to untested features.

    Regards,
    Victor
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  8. Sacha
    Sacha avatar
    10 posts
    Member since:
    Sep 2015

    Posted 23 Jun in reply to Victor Link to this post

    Cool thanks. Another workaround is to set this in the RadDataForm layout xml:

    android:saveEnabled="false"

Back to Top
DevCraft banner