Android: onSaveInstanceState not being called from activity
Asked Answered
I

4

72

I have an Activity A which calls Activity B. In Activity B, when i click on a button, finish() is called, which in turn calls onDestroy() of Activity B and returns to activity A.

According to android documentation, Before onDestroy is called, onSaveInstanceState(Bundle bundle) will be called, where i do the following.

@Override
    public void onSaveInstanceState(Bundle outState) {

        super.onSaveInstanceState(outState);
        System.out.println("Saving webview state");
        Log.d(TAG, "In onsave");
        wv.saveState(outState);

    }

and the next time Activity B is started from Activity A,

in the oncreate(), i do the following:

onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);

if(savedInstanceState != null){
//restore webview
}else {
// code
}
}

However, before calling onDestroy in Activity B, The onSaveInstanceState method is never called. any help on this will be greatly appreciated.

EDIT: if this is not possible. Please let me know if there is a way to store webview state

Impalpable answered 9/10, 2012 at 4:59 Comment(1)
what does wv stand for?Metathesis
J
364

I had a similar situation. It was clearly a dev bug. I've overridden the wrong method:

public void onSaveInstanceState(Bundle outState, 
                                PersistableBundle outPersistentState)

Instead a correct one:

protected void onSaveInstanceState(Bundle outState)
Juanajuanita answered 19/11, 2015 at 11:1 Comment(9)
Code completion suggested this method was part of FragmentActivity, which was enough to cause confusion for me.Newburg
In fact it's not a bug, there is another overload method of onSaveInstanceState but its modifier is protected not public. And the protected overload is what we need to override to save the states.Hirschfeld
Judging on popularity of this answer, I guess using using the same name for different purposes was not an excellent API choice.Abecedarian
What are the difference between the two?Alidaalidade
From documentation: This is the same as onSaveInstanceState(Bundle) but is called for activities created with the attribute R.attr.persistableMode set to persistAcrossReboots. The PersistableBundle passed in will be saved and presented in onCreate(Bundle, PersistableBundle) the first time that this activity is restarted following the next device reboot.Rentroll
It went unnoticed until your comment, thanks a lot, made my dayToothache
Yeah, I've wasted a lot of time when searching for it.Abecedarian
I always forget about this... media.makeameme.org/created/clever-girl-5b1b38.jpgButacaine
Thank you so much for your answer, I wasted many hours trying to figure out why my code wasn't working, this was the problem all along.Phage
B
9

See the doc here: http://developer.android.com/reference/android/app/Activity.html

Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.

The documentation of onSaveInstanceState method says,

Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.

try this:

@Override
public void onPause(){
   System.out.println("Saving webview state");
    Log.d(TAG, "In onsave");
    wv.saveState(outState);
    super.onPause();

}

and
@Override
 public void onResume(){
     //restore webview
 }

I am not sure what is the purpose of that if statement, but try this and see what happens.

Butz answered 9/10, 2012 at 5:4 Comment(5)
Thanks for the quick response. But how do i save it in onPause()? can you please help me on this?Impalpable
The problem is, i do not want to restore the webview in onResume. I want to do it in onCreate()Impalpable
you can do that. Since you called finish(), when you come back again, onCreate() will be called first and then onResume(). So you can put them in either one. You can try to move those code to onCreate() and see the result. Just try it out, it won't hurt.Butz
in onpause(), the bundle "outstate" is part of the activity declared as a class variable Bundle outstate; When the activity is started again. in onCreate and onResume the bundle outstate will be null.Impalpable
+1 thank you for the excellent reasons to why onSaveInstanceState may not be called.Fullblown
J
3

Eventually you're going to have to write the the back/history to persistent storage. In the case of the device being shut down as one example, as well as avoiding a contrived (in my opinion) example where you call onSaveInstanceState in onPause (what you'll need to do to get the bundle you want passed into onRestoreInstanceState which you can then pass into restoreState).

Therefore, besides reconsidering your design (if the user closed your application and you're not making a browser, do they really want to keep the same history?), you should look up SharedPreferences and how to use them.

Unfortunately you cannot put a bundle in shared preferences, nor would I recommend trying to write the bundle via Parcelable (it's only meant for IPC, not persistent storage). But what you can do is store all the primitives that the bundle stores. This might be contrived too, but it seems to me the only way to get permanent storage.

And then rebuild your bundle via the primitives stored in SharedPreferences, and pass that into restoreState(). You can check the Android source code to see what webView.saveState() actually does (I looked up the 2.1 code and it seems to write a int, a serializeable object, and then another bundle for the SSL cert. The SSL cert bundle itself is just four integers). Off the top of my head, I'd just write all the primitives you can, and then store the location (string) of the local file you write the serialized data too.

Even if you have some ordered collection of the entire BackForward list, I'm not sure how to translate that into the goBack() and goForward() using those values (there's a protected method that's involved in adding items to the list but you can't access that). UNLESS you do use restoreState(), which is why we're going to all the work to rebuild the bundle correctly.

Seriously though, unless my search skills are abysmal (entirely possible), storing the WebView history in places beyond where saveInstanceState/restoreInstanceState can do your work for you doesn't seem to be a problem a lot of people have run into. I.e. not a lot of people are trying to persist the WebView history when the user explicitly closes their application, so you have to ask yourself why are YOU doing this?

Apologies if there is a really easy way to persistently store this information and reload into a WebView btw!

Joyejoyful answered 9/10, 2012 at 7:42 Comment(3)
Hi aamit. I do not want to keep track of the history of the webview. i just have one url for my site and i use ajax to load data. Overview as to what i want to implement, in onCreate() i load a url. when i call finish() -> destroy(). the next time i come to the activity, oncreate is called again and the url is loaded again. This creates a new session wherein, whatever cookies where present on the webview are now gone. To get the cookies, ill have to start the cookie creation process all over again, which is what i do not want to do. im an still a learner in android dev. any help wil be g8.Impalpable
I realize saveinstancestate is not the solution for my problem.Impalpable
Hey Bharath, sorry for making such broad assumptions about your program. Have you tried looking at CookieSyncManager? Unfortunately I don't know a lot about handling cookies in Android but it seems to be what you're looking for - a way to store cookies.Joyejoyful
B
0

for call onSaveInstance method please just use

public void onSaveInstanceState(Bundle outState)

for save a value not need use

public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState)
Bitters answered 27/10, 2019 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.