25

I've been programming for Android for some time, and I'm still looking for solutions to retain data over configuration changes. Aside from saving Parcelables to Activity's Bundle in onSaveInstanceState docs are suggesting using Fragment with setRetainInstance flag set to true.

But I've just come across some code that uses onRetainCustomNonConfigurationInstance to hold arbitrary objects (in a fancy way, but essentially big objects without references to Activity etc.). I have never seen this method used, so I have some doubts:

  • Is this method safe to call to store arbitrary objects (in a sense that I can be pretty sure it's gonna get called, and that it won't be deprecated/removed anytime soon)?
  • How is this method different from onRetainNonConfigurationInstance(), which also should return Object, and in essence should work similarly?
  • Is using retained fragment still better, for some reason?

As a bonus, I would be grateful for any other tips or solutions to save state of objects like AsyncTask, Observable, view's presenters and go on

wasyl
  • 3,421
  • 3
  • 27
  • 36
  • 1
    http://stackoverflow.com/questions/15749106/onsaveinstancestate-vs-onretaincustomnonconfigurationinstance – petey Jun 25 '15 at 21:38
  • I use `android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"` for my `Activities`. Taken from https://developers.google.com/admob/android/quick-start. Supposedly this is not the "best" solution but it works better than anything I have seen. – Jared Burrows Jun 29 '15 at 16:15
  • 2
    @JaredBurrows I appreciate your comment, but I share opinion that it's not only *not the best solution*, but that it's wrong and harmful way to handle state loss in Android apps. Plus it doesn't really solve the problem (after app goes to background, for example) – wasyl Jun 29 '15 at 19:05
  • You contradicted yourself and yes it does that problem. If you app goes in the background, it doe retain the data(eg. RecyclerView data). – Jared Burrows Jun 29 '15 at 20:55
  • See http://stackoverflow.com/a/16305144/950427 – Jared Burrows Jun 29 '15 at 23:48
  • 1
    @JaredBurrows: I agree with wasyl, in that your solution does not really address any problems. At best, you can use your approach as an optimization for activities that lock themselves to some particular screen orientation. Otherwise, you still have to deal with all the rest of the configuration changes (e.g., locale, car dock) *and* you now have to fuss with dealing with each individual resource change in an `onConfigurationChanged()` method to cover the cases where `configChanges` blocks the normal activity destroy/recreate cycle. – CommonsWare Jul 15 '15 at 11:02
  • 1
    "that it won't be deprecated/removed anytime soon" -- it's in a library. You control when you take on newer versions of the library. "How is this method different from onRetainNonConfigurationInstance()" -- `onRetainNonConfigurationInstance()` is `final` and cannot be overridden, to ensure that `FragmentActivity` can do configuration-change work with its fragments. `onRetainCustomNonConfigurationInstance()` is the replacement "hook" to participate in this at the activity level. "Is using retained fragment still better, for some reason?" -- it works in places other than `FragmentActivity`. – CommonsWare Jul 15 '15 at 11:06
  • I already said it isn't the best solution in my comment. Thanks for agreeing with me twice. – Jared Burrows Jul 15 '15 at 13:36
  • @CommonsWare Thanks! So basically it's my choice to either use retained fragment or custom nonConfiguration class, and both should work in a similar fasion, correct? – wasyl Jul 15 '15 at 14:22
  • 1
    "both should work in a similar fasion, correct?" -- insofar as both should be retained across configuration changes, yes. – CommonsWare Jul 15 '15 at 14:33

1 Answers1

20

Is this method safe to call to store arbitrary objects (in a sense that I can be pretty sure it's gonna get called, and that it won't be deprecated/removed anytime soon)?

onRetainCustomNonConfigurationInstance() is a relatively new method and it is not deprecated. I would really assume it is not going to disappear soon, because there is no reason for introducing something new just to remove it. You can use it safely.

How is this method different from onRetainNonConfigurationInstance(), which also should return Object, and in essence should work similarly?

onRetainNonConfigurationInstance() always return an instance of inner NonConfigurationInstances class with retained fragments, loaders etc states. You cannot (and should not) change this system behavior. That's why the method is final and you cannot override it.

If you want to retain your custom instance, you need to override onRetainCustomNonConfigurationInstance() and return it from there.

In fact, onRetainNonConfigurationInstance() calls onRetainCustomNonConfigurationInstance() and retains retuned instance with the other states like retained fragments and loaders.

Is using retained fragment still better, for some reason?

It is rather a matter of your use case and preferences. The logic might be like this. If your activity just controls fragments and has no other special logic in it, then it is easier to use retained fragments. If your activity has something to retain, then you can safely use onRetainCustomNonConfigurationInstance() method. As for now, in both cases the state still gets retained by good old and deprecated onRetainNonConfigurationInstance() method.

p.s. Regarding the bonus question about storing a state I would rather suggest to look at onSaveInstanceState() method. It was intended for storing states.

Update: AndroidX release from November 5, 2018 deprecated the method with the following note: onRetainCustomNonConfigurationInstance has been deprecated. Use a ViewModel for storing objects that need to survive configuration changes.

sergej shafarenka
  • 20,071
  • 7
  • 67
  • 86
  • Thanks for the answer! Can you comment on part of [Activity source](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/Activity.java), line 1758, javadoc for `onRetainNonConfigurationInstance()` method, which says *This function is called purely as an optimization, and you must not rely on it being called.*? – wasyl Jun 26 '15 at 09:59
  • ´onRetainNonConfigurationInstance()´ os deprecated, that's why you should not rely on it and you don't need to, because you should either use retained Fragment or ´onRetainCustomNonConfigurationInstance()´ one which does not have this warning. – sergej shafarenka Jun 26 '15 at 11:26
  • 1
    Sure, but `FragmentActivity`, the one which provides `onRetainCustomNonConfigurationInstance`, uses `onRetainNonConfigurationInstance`, which in `Activity` class (so its parent) is marked as not reliable. So in `FragmentActivity` method `onRetainCustom...` is called from `onRetainNonConf...` which is overriden from parent, while parent's docs say it's not guaranteed to be called. Sorry if I'm unclear, let me know if I need to reword what I mean ;) – wasyl Jun 26 '15 at 14:11
  • 1
    I would just stick to the API as the official contract between Android Framework and developers. It says "don't use onRetainNonConfigurationInstance" through its deprecation and it says "you can use FragmentActivity.onRetainCustomNonConfigurationInstance()" because its a public, not deprecated method. The fact one method calls another one should not change anything. Once deprecated methods gets removed or not called, they still have to provide support for another method (because its a part of official API) in some way. There is some probability they break the rule, but imho it's not so high. – sergej shafarenka Jun 29 '15 at 21:14
  • This answer together with CommonsWare's comments to the question fully answer my questions, thanks a lot – wasyl Jul 15 '15 at 15:07
  • 3
    As of november 2018, the `onRetainNonConfigurationInstance` method is deprecated: https://developer.android.com/jetpack/androidx/androidx-rn#2018-nov – Mavamaarten Nov 06 '18 at 08:17