I'm at a dead end. I use Dagger 2 for dependency injection, but I lose state when the application goes into the background. Here is the scenario: the application starts and creates dependencies. Everything works fine as long as the application remains in the foreground. However, there is a scenario where the application should go into the background. When it returns, the values stored in one of my entered classes are lost.
For my introduced classes, which do not have their own dependencies, everything seems to be restored correctly. However, there is one class introduced that has a nested dependency, and one that is not being restored. This is how I configure it:
AppComponent.java
@Singleton @Component( modules = { AppModule.class } ) public interface AppComponent { SessionKeyExchangerService provideSessionKeyExchangerService(); AESCipherService provideCipherService(); void inject(LoginActivity loginActivity); }
Appmodule.java
@Module public class AppModule { @Provides @Singleton AESCipherService provideCipherService() { return new AESCipherService(); } @Provides @Singleton SessionKeyExchangerService provideSessionKeyExchangerService(AESCipherService service) { return new SessionKeyExchangerService(service); } }
And then, when I go to introduce these dependencies, I do it like this:
LoginActivity.java
@Inject SessionKeyExchangerService sessionKeyExchangerService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); Injector.INSTANCE.getAppComponent().inject(this); if (savedInstanceState != null) { sessionKeyExchangerService = savedInstanceState.getParcelable(SESSION_KEY_PARCEL); Log.d(Constants.TAG, "session key retrieved in on create: " + sessionKeyExchangerService.getCipherService().getBase64EncodedSessionKey()); } }
So, my main question is how to maintain the state of the introduced Dagger 2 class. I am happy to share more code, but this is the main idea.
Thanks for any help.
EDIT Assuming that what I did above is fine, let me go on to how I save and retrieve the values stored in these injected objects. This will show that there is a problem somewhere.
When I fade into the background and then come back, I see that I am getting a new PID. I also see that I can correctly store and receive the entered values in the LoginActivity class. However, other classes that also have a reference to the entered value now have different meanings, which means that their reference to another memory location, right?
My best guess about where I am wrong is in LoginActivity onCreate, where I restore the value of sessionKeyExchangerService from the saved sessionKeyExchangerService . I think that I am creating new values that are not recognized in the application as nested dependencies, but I do not know why this is wrong or how to fix it.
This code is also located in LoginActivity.java:
@Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(SESSION_KEY_PARCEL, sessionKeyExchangerService); Log.d(Constants.TAG, "session key saved: " + sessionKeyExchangerService.getCipherService().getBase64EncodedSessionKey()); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); sessionKeyExchangerService = savedInstanceState.getParcelable(SESSION_KEY_PARCEL); Log.d(Constants.TAG, "session key retrieved in on restore state: " + sessionKeyExchangerService.getCipherService().getBase64EncodedSessionKey()); }
Here is the console output that illustrates the problem. Note 1) how the PID changes after onStop() and 2) how the Authenticator class (having a reference to AESCipherService has a different session key value:
1398-1398 / com.mysite.myapp D / MYTAG: instance save state
1398-1398 / com.mysite.myapp D / MYTAG: session key saved: 93Zuy8B3eos + eCfBQk9ErA ==
1398-1398 / com.mysite.myapp D / MYTAG: on stop - 3562-3562 / com.mysite.myapp D / MYTAG: session key obtained on on create: 93Zuy8B3eos + eCfBQk9ErA ==
3562-3562 / com.mysite.myapp D / MYTAG: at startup
3562-3562 / com.mysite.myapp D / MYTAG: session key restored in recovery state: 93Zuy8B3eos + eCfBQk9ErA ==
3562-3562 / com.mysite.myapp D / MYTAG: the authenticator class says the session key is: 28HwdRCjBqH3uFweEAGCdg ==
SessionKeyExchangerService.java
protected SessionKeyExchangerService(Parcel in) { notifyOn = in.readString(); sessionKeyExchangeAttempts = in.readInt(); MAX_SESSION_KEY_EXCHANGE_ATTEMPTS = in.readInt(); sessionKeyExchangeHasFailed = (in.readByte() == 1); cipherService = in.readParcelable(AESCipherService.class.getClassLoader()); } public static final Creator<SessionKeyExchangerService> CREATOR = new Creator<SessionKeyExchangerService>() { @Override public SessionKeyExchangerService createFromParcel(Parcel in) { return new SessionKeyExchangerService(in); } @Override public SessionKeyExchangerService[] newArray(int size) { return new SessionKeyExchangerService[size]; } }; @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(notifyOn); dest.writeInt(sessionKeyExchangeAttempts); dest.writeInt(MAX_SESSION_KEY_EXCHANGE_ATTEMPTS); dest.writeByte((byte) (hasSessionKeyExchangeFailed() ? 1 : 0)); dest.writeParcelable(cipherService, flags); }
AESCipherService.java
protected AESCipherService(Parcel in) { sessionKeyBytes = in.createByteArray(); ivBytes = in.createByteArray(); sessionId = in.readLong(); mIsSessionKeyEstablished = (in.readByte() == 1); verbose = (in.readByte() == 1); } public static final Creator<AESCipherService> CREATOR = new Creator<AESCipherService>() { @Override public AESCipherService createFromParcel(Parcel in) { return new AESCipherService(in); } @Override public AESCipherService[] newArray(int size) { return new AESCipherService[size]; } }; @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(sessionKeyBytes); dest.writeByteArray(ivBytes); dest.writeLong(sessionId); dest.writeByte((byte) (isSessionKeyEstablished() ? 1 : 0)); dest.writeByte((byte) (verbose ? 1 : 0 )); }