Why is my custom object not persisted by onSaveInstanceState and onRestoreInstanceState - android

When the activity gets called for the very first time, it is called with an extra in the intent. The extra is received and stored in the data member:
class EditBlindScheduleActivity extends Activity
{
private BlindSchedule blindSchedule;
protected void onCreate(Bundle savedInstanceState)
{
...
if (savedInstanceState == null) { // Not recreating, first load.
blindSchedule = (BlindSchedule) getIntent().getSerializableExtra("blindSchedule");
}
There is a simple if/else to determine if we have the blindSchedule object or not.
if (blindSchedule == null) {
setTitle("Create Blind Schedule");
} else {
setTitle("Edit Blind Schedule");
}
When I load the activity for the first time, indeed, the title is "Edit Blind Schedule", meaning there is a blindSchedule object.
Unfortunately, when I rotate the screen twice the title reads "Create Blind Schedule", meaning the blindSchedule object is null and has failed to be persisted.
Why is my blindSchedule object not being persisted, and what can I do about it?
Full code follows:
public class EditBlindScheduleActivity extends Activity {
private BlindSchedule blindSchedule;
Boolean creating; // Creating or updating?
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_blind_schedule);
if (savedInstanceState == null) { // Not recreating, first load.
blindSchedule = (BlindSchedule) getIntent().getSerializableExtra("blindSchedule");
}
if (blindSchedule == null) {
creating = true;
setTitle("Create Blind Schedule");
} else {
creating = false;
setTitle("Edit Blind Schedule");
}
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
blindSchedule = (BlindSchedule) savedInstanceState.getSerializable("blindSchedule");
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("blindSchedule", blindSchedule);
}

You need to retrieve the saved custom object in onCreate in your case.
According to Official Documentation
onRestoreInstanceState is called after onStart by which time your setTitle has already been called.
Add an else part to the if (savedInstanceState == null) and retrieve blindSchedule in there same way as you do for your getIntent
if (savedInstanceState == null)
{ // Not recreating, first load.
blindSchedule = (BlindSchedule) getIntent().getSerializableExtra("blindSchedule");
}
else
{
blindSchedule = (BlindSchedule) savedInstanceState.getSerializableExtra("blindSchedule");
}

Related

Android: Save XWalkView - Crosswalk state

I am using XWalkView to show a mobile web site as an application. My problem is when application goes background and comes back it reloads the page it shows. I want to keep it state and continue from that state when it comes from background. Here is my code:
public class MainActivity extends AppCompatActivity {
static final String URL = "https://www.biletdukkani.com.tr";
static final int MY_PERMISSIONS_REQUEST_ACCESS_LOCATION = 55;
static final String SHOULD_ASK_FOR_LOCATION_PERMISSION = "shouldAskForLocationPermission";
static final String TAG = "MainActivity";
static final String COMMAND = "/system/bin/ping -c 1 185.22.184.184";
static XWalkView xWalkWebView;
TextView noInternet;
static Bundle stateBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
stateBundle = savedInstanceState.getBundle("xwalk");
}
setContentView(R.layout.activity_main);
initNoInternetTextView();
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
stateBundle = savedInstanceState.getBundle("xwalk");
Log.d(TAG, "onRestoreInstanceState");
}
/**
* İnternet yok mesajı gösteren TextVidew'i ayarlar.
*/
private void initNoInternetTextView() {
Log.d(TAG, "initNoInternetTextView");
noInternet = (TextView) findViewById(R.id.no_internet);
if (noInternet != null) {
noInternet.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
checkInternetConnection();
}
});
}
}
/**
* WebView'i ayarlar.
*/
private void initWebView() {
Log.d(TAG, "initWebView");
if (xWalkWebView == null) {
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
xWalkWebView = (XWalkView) findViewById(R.id.webView);
//xWalkWebView.clearCache(true);
xWalkWebView.load(URL, null);
xWalkWebView.setResourceClient(new BDResourceClient(xWalkWebView, progressBar));
}
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
checkLocationPermissions();
checkInternetConnection();
if (xWalkWebView != null && stateBundle != null) {
xWalkWebView.restoreState(stateBundle);
}
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
if (xWalkWebView != null) {
stateBundle = new Bundle();
xWalkWebView.saveState(stateBundle);
}
}
public void onSaveInstanceState(Bundle savedInstanceState) {
Log.d(TAG, "onSaveInstanceState");
// Save the user's current game state
savedInstanceState.putBundle("xwalk", stateBundle);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onBackPressed() {
Log.d(TAG, "onBackPressed");
if (xWalkWebView != null && xWalkWebView.getNavigationHistory().canGoBack()) {
xWalkWebView.getNavigationHistory().navigate(XWalkNavigationHistory.Direction.BACKWARD, 1);
} else {
super.onBackPressed();
}
}
}
I have also tried to add following lines to manifest but didn't work.
android:launchMode="singleTask"
android:alwaysRetainTaskState="true"
How can i do that?
Thanks in advcance.
One way would be to initialize the view inside a fragment which is set to retain it's instance.

Android Save Instance - Best Practice

So in order to save the instance of my Fragment, I use a Bundle which I save in onSaveInstanceState and restore in onActivityCreated. Now I'm wondering what the best practice is:
1) Have a bundle where you store variables in, and use/update as required in your code. This way saving and restoring states' code is very short. Something like this:
private Bundle mDataValues = new Bundle();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if ( (savedInstanceState != null) && (savedInstanceState.getBundle("mDataValues") != null) ) {
this.mDataValues = savedInstanceState.getBundle("mDataValues");
}
public void someFunction() {
if (this.mDataValues == null) {
// Should not be possible on the times we call this function
return;
}
usernameView.setText(mDataValues.getString(Constants.BUNDLE_KEY_USERNAME));
personnameView.setText(mDataValues.getString(Constants.BUNDLE_KEY_PERSONNAME));
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putBundle("mDataValues", mDataValues);
}
2) Have a bunch of variables declared in the fragment, and use these in your code. Something like this:
private String mUsername;
private String mPersonname;
#Override
public void onActivtyCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if ( savedInstanceState != null ) {
mUsername = savedInstanceState.getString("username");
mPersonname = savedInstanceState.getString("personname");
}
}
public void someFunction() {
usernameView.setText(mUsername);
personnameView.setText(mPersonname);
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("username", mUsername);
outState.putString("personname", mPersonname);
}
The amount of variables above is of course a lot less than in the actual code written. So what is the best practice? Or are both viable in specific situations?

Is it save to overrwrite the savedInstanceState bundle after passing it up?

I have the following (to avoid checking if a fragment is being created newly or just being recreated)
#Override public void onActivityCreated(Bundle args) {
super.onActivityCreated(args);
if (this.getArguments() != null) args = this.getArguments();
// rest of fragment loading goes here
}
Not sure what you are trying to do never seen budle values being overwritten.
If you want some values to be availbale inside fragment pass those values to activity and inside fragment call getActivity().getIntent().getExtra(
Otherwise have a look at code below if want save some fragment data if fragment is destroyed
Inside fragment in onCreate method check if savedInstanceState is null or not
#Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
//fragment recreated
}
}
Save data as follows
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (jsonObject != null) {
outState.putString(Constants.JSON, jsonObject.toString());
}
}

how to set listview's position after configuration change

I'm struggling to recover my position in a listview on screen rotation configuration change.
Amongst the many things I've tried I came to this:
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState == null) {
...
mVisibleItem = -1;
} else {
if (savedInstanceState.containsKey(LV_VISIBLE_ITEM)) {
mVisibleItem = savedInstanceState.getInt(LV_VISIBLE_ITEM);
}
}
setRetainInstance(true);
}
and here I'm trying to set the position in the listview
#Override
public void onResume() {
super.onResume();
if (mVisibleItem > 0) {
mlvDictionaryIndex.setSelectionFromTop(mVisibleItem, 0);
}
}
However, much to my surprise, after rotating the screen and watching mVisibleItem gets set with the correct value, in onResume I see that mVisibleItem equals -1. How come?
use onSavedInstanceState to write in the bundle the returned value of ListView.onSaveInstanceState(), and restored it onActivityCreated
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mListView != null) {
outState.putParcelable(LISTVIEW_INTERNAL_STATE_KEY, mListView.onSaveInstanceState());
}
}
after the data are reload then you can call
mListView.onRestoreInstanceState(savedInstanceState.getParcelable(LISTVIEW_INTERNAL_STATE_KEY));
Override onSaveInstanceState such as below"
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("pos", pos);
}
Then in your onCreate method have read the savedInstanceState to check if this is an orientation change or a new activity.
private int pos = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
//This is a new activity
}else{
pos = savedInstanceState.getInt("");
}
Now you have the position in the list, and you can scroll to this in configuration change.
Maybe after the data in the listview is reloaded,the code below will work.
mlvDictionaryIndex.setSelectionFromTop(mVisibleItem, 0);
So you can use post() method, just like below:
post(new Runnable() {
public void run() {
mlvDictionaryIndex.setSelectionFromTop(mVisibleItem, 0);
}
});

ProgressBarIndeterminateVisibility reappears on change rotation

i have a problem with my app. if i click the button to stop the ProgressBarIndeterminate in actionbar, when i rotate the screen it reappear. can i stop it forever? thanks
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_main);
setProgressBarIndeterminateVisibility(true);
}
public void test(View v) {
setProgressBarIndeterminateVisibility(false);
}
sorry for my english
When you rotate your screen, the Activity gets created again (onCreate will get invoked again), so you will call setProgressBarIndeterminateVisibility(true) which will make it reappear.
To keep track of whether or not you've clicked the stop button, you will need to save the state somehow (consider implementing onSaveInstanceState and then retrieving the stored value in onCreate, or saving the state to a shared preference/database).
onSaveInstanceState --> invoked when your Activity is torn down due to the rotation
private boolean showProgressBarVisibility = true; //always show the first time
#Override
public void onCreate(Bundle savedInstanceState){
if(savedInstanceState != null && savedInstanceState.containsKey("user3744384_pressed_the_button"){
showProgressBarVisibility = false
}
setProgressBarIndeterminateVisibility(showProgressBarVisibility);
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString("user3744384_pressed_the_button", true);
}
do something like this in onCreate:
if(savedInstanceState !=null){
setProgressBarIndeterminateVisibility(false);
}
but you should also save the state in public void onSaveInstanceState(Bundle ...).. research on how activities save their state.
when orientation changes android kills your activity and onCreate is called.. you can save your app state and restore it.
override this method to save state
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(key, yourstatevariable);
}
and get your state variable in onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
if (savedInstanceState != null) {
String yourstatevariable = savedInstanceState.get(key);
}
}

Categories

Resources