Je suis dans une impasse. J'utilise Dagger 2 pour l'injection de dépendance, mais je perds l'état lorsque l'application passe en arrière-plan. Voici le scénario: l'application démarre et crée les dépendances. Tout fonctionne parfaitement tant que l'application reste au premier plan. Cependant, il existe un scénario dans lequel l'application doit passer en arrière-plan. Quand il revient, les valeurs stockées dans l'une de mes classes injectées sont perdues.Dague 2 Enregistrer et restaurer l'état lorsque l'activité s'arrête
Pour mes classes injectées qui n'ont aucune dépendance propre, tout semble se rétablir correctement. Cependant, il y a une classe injectée qui a une dépendance injectée, et c'est celle qui ne récupère pas. Voici comment je suis mise en place:
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);
}
}
Et puis quand je vais à injecter ces dépendances, je le fais comme ceci:
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());
}
}
Alors, ma question fondamentale est de savoir comment maintenir l'état d'un poignard 2 classe injectée. Je suis heureux de partager plus de code, mais c'est l'idée essentielle.
Merci pour toute aide.
EDIT En supposant que ce que je l'ai fait ci-dessus est OK, laissez-moi passer à comment j'enregistrer et récupérer les valeurs stockées dans les objets injectés. Cela montrera qu'il y a un problème quelque part. Lorsque je passe en arrière-plan et que je reviens, je peux voir que je reçois un nouveau PID. Je peux également voir que je suis capable de stocker et de récupérer correctement les valeurs injectées dans la classe LoginActivity. Cependant, d'autres classes qui ont également une référence à la valeur injectée ont maintenant des valeurs différentes ce qui signifie que leur référence est à un emplacement de mémoire différent, non?
Ma meilleure estimation de l'endroit où je vais mal est dans LoginActivity onCreate où je restaure la valeur sessionKeyExchangerService
de la parcelle sauvegardée. Je pense que je crée de nouvelles valeurs qui ne sont pas reconnues dans l'application comme des dépendances injectées, mais je ne sais pas pourquoi c'est faux ou comment y remédier.
Ce code est également 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());
}
est ici la sortie de la console qui illustre la question. Remarque 1) comment les changements PID après onStop()
est appelé, et 2) comment la classe Authenticator
(qui a une référence à AESCipherService
a une valeur clé de session différente:
1398-1398/com.mysite.myapp D/MYTAG: à l'état d'instance de sauvegarde
1398-1398/com.mysite.myapp D/MYTAG: clé de session enregistrée: 93Zuy8B3eos + eCfBQk9ErA ==
1398-1398/com.mysite.myapp D/MYTAG: sur arrêt
3562-3562/com.mysite.myapp D/MYTAG: clé de session récupérée dans sur la création: 93Zuy8B3eos + eCfBQk9ErA ==
3562-3562/com.mysite.myapp D/MYTAG: au démarrage
3562-3562/com.mysite.myapp D/MYTAG: clé de session récupérée dans le état de restauration: 93Zuy8B3eos + eCfBQk9ErA ==
3562-3562/com.mysite.myapp D/MYTAG: classe authentificateur dit que le clé de session est: 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));
}
Pouvez-vous indiquer le code dans lequel vous injectez votre activité et où construisez-vous le graphique? – Ognyan
Je reviens finalement à cette question. J'ai réécrit la question pour me concentrer sur la façon dont j'ai mis en place l'injection de dépendance plutôt que sur les parcelables. Je suis assez confiant que je fais cette partie correctement, donc l'erreur doit être dans la partie Dagger 2. – Alex
Je crois que vous devriez sérialiser l'état de ce que vous fournissez dans votre module par 'onSaveInstanceState()' et le hacker dans 'onRestoreInstanceState()', considérant que la mort du processus tue tout le processus applicatif et que seuls les bundles survivent. Vous devrez probablement construire votre composant dans 'onRestoreInstanceState()' s'il n'existe pas, et le remettre en place une fois en instanciant vos dépendances à travers les méthodes de provisionnement du composant. – EpicPandaForce