0

I have the following scenario: I have a model class, which looks like this:

public class UserModel implements Serializable {
    private String userEmail, userName;

    public UserModel() {}

    public UserModel(String userEmail, String userName) { this.userEmail = userEmail; this.userName = userName;}

    //setters and getters
}

In my first activity, I'm logging in to Firebase, I'm getting the data from the FirebaseUser object and then I'm creating an object of the UserModel class and passing it to intent like this:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("userModel", userModel);
startActivity(intent);

In the second activity, every time it starts, I'm checking if the user is logged in or not. If it is, it stays here, if not I redirect to the first activity. Here, I'm getting the object using the following line of code:

UserModel userModel = (UserModel) getIntent().getSerializableExtra("userModel");

First time when the activity starts, everything works fine, but when I restart the activity, I get a NullPointerException. How can I preserve the userModel object that I got from the intent through any activity restarts?

Thanks in advance!

Dimitar
  • 4,402
  • 4
  • 31
  • 47
Joan P.
  • 2,368
  • 6
  • 30
  • 63
  • use `LiveData` and `ViewModel` class for that. – KuLdip PaTel Dec 27 '17 at 12:57
  • 1
    Best Solution i found... http://www.lucazanini.eu/en/2014/android/restoring-complex-objects-restart-activity/ – Nikhil Borad Dec 27 '17 at 12:58
  • @SripadRaj Why to use `SharedPreferences` and not an Intent? What is wrong with that? – Joan P. Dec 27 '17 at 12:58
  • @KuLdipPaTel What do you mean through `LiveData and ViewModel`? – Joan P. Dec 27 '17 at 12:59
  • @IoanaP. sorry, I guess, I misunderstood your question. But to answer your question, Sharedprefs data could be accessed any time, but in Intents, you wont get the data if you dont pass the intent. When the activity restarts you might not be getting your data through the intent. So it throws NPE. – SripadRaj Dec 27 '17 at 13:01
  • try this https://stackoverflow.com/questions/10810418/whats-oncreatebundle-savedinstancestate – avez raj Dec 27 '17 at 13:04
  • @loana you can save your model in sharedPrefrences, database or make a service for that ? – Umair Dec 27 '17 at 13:05

2 Answers2

2

You should have a look at the Activity Lifecycle. You'll find a method called onSavedInstanceState(). Now what you want to do is store the object of your class in the bundle using that method, and get it back in onCreate(), as follows:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        UserModel userModel = (UserModel) savedInstanceState.getSerializable("userModel");
    } else if (getIntent() != null) {
        UserModel userModel = (UserModel) getIntent().getSerializableExtra("userModel");
    } else {
        // These is no data
    }

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("userModel", userModel);
}
Kartik Arora
  • 571
  • 4
  • 10
  • I'm getting a `NullPointerException` when I switch between applications. Seems that when `onPause` is called, my object is also `null`. Why is this happening? – Joan P. Dec 27 '17 at 13:28
1

You have to persist the model to external storage. Some viable options are:

  • SharedPreferences: save in onPause(), restore in onResume() or onCreate(); here is a quick example.
  • SaveInstanceState

For example through SaveInstanceState by overriding the following callbacks:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);

    /* savedInstanceState Bundle will be passed onto onCreate() when activity
     * gets killed and restarted. */
     savedInstanceState.putSerializable("userModel", userModel);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    /* Also being passed onto onCreate(). */
    UserModel mUserModel = (UserModel) savedInstanceState.getSerializable("userModel");
}

By doing a null-check against the intent first, you can save yourself some processing time, while not doing any redundant operations.

Dimitar
  • 4,402
  • 4
  • 31
  • 47
  • Bundle objects do not have `getSerializableExtra()`. – Kartik Arora Dec 27 '17 at 13:14
  • 1
    I missed it in the haste, while copying from the question. Have edited it. – Dimitar Dec 27 '17 at 13:18
  • If i make `mUserModel` a global variable, I get `NullPointerException` when I'm trying to use `mUserModel` object through my activity. – Joan P. Dec 27 '17 at 13:35
  • Yes, `saveInstanceState` recreates the activity instance, only after it has been preempted by the Android scheduler. Therefore, to respond correctly to user-provoked context switches, you have to instead revert to `SharedPreferences` and save the state in `onPause()`. – Dimitar Dec 27 '17 at 14:45
  • So in my case, I can only use `SharedPreferences`? – Joan P. Dec 27 '17 at 14:50
  • Mostly yes, it is the most straightforward way to go. For all possible options, refer to [Android Storage Options](https://developer.android.com/guide/topics/data/data-storage.html). – Dimitar Dec 27 '17 at 14:52