我陷入了僵局。我正在使用 Dagger 2 进行依赖项注入(inject),但是当应用程序进入后台时我正在丢失状态。这是场景:应用程序启动并创建依赖项。只要应用程序停留在前台,一切都可以完美运行。但是,在某些情况下,应用程序必须进入后台。当它返回时,存储在我注入(inject)的类之一中的值丢失了。
对于我自己没有依赖关系的注入(inject)类,一切似乎都能正确恢复。但是,有一个注入(inject)的类具有注入(inject)的依赖项,而这个是无法恢复的。这是我的设置方式:
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);
}
}
然后当我去注入(inject)这些依赖项时,我会这样做:
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());
}
}
因此,我的基本问题是如何维护 Dagger 2 注入(inject)类的状态。我很乐意分享更多代码,但这是基本思想。
感谢您的帮助。
编辑 假设我上面所做的没有问题,让我继续讨论如何保存和检索存储在这些注入(inject)对象中的值。这将表明某处存在问题。
当我进入后台,然后再回来时,我可以看到我得到了一个新的 PID。我还可以看到,我能够在 LoginActivity 类 中正确存储和检索注入(inject)的值。但是,其他也引用注入(inject)值的类现在有不同的值,这意味着它们的引用指向不同的内存位置,对吧?
我对哪里出错的最佳猜测是在 LoginActivity onCreate 中,我在其中从已保存的包裹中恢复 sessionKeyExchangerService
值。我想我正在创建新的值,这些值在应用程序中未被识别为注入(inject)的依赖项,但我不知道为什么这是错误的或如何修复它。
此代码也在 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());
}
这是说明问题的控制台输出。注意 1) 在调用 onStop()
之后 PID 是如何变化的,以及 2) Authenticator
类(它引用了 AESCipherService
)是如何变化的不同的 session key 值:
1398-1398/com.mysite.myapp D/MYTAG﹕ on save instance 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 retrieved in on create: 93Zuy8B3eos+eCfBQk9ErA==
3562-3562/com.mysite.myapp D/MYTAG﹕ on start
3562-3562/com.mysite.myapp D/MYTAG﹕ session key retrieved in on restore state: 93Zuy8B3eos+eCfBQk9ErA==
3562-3562/com.mysite.myapp D/MYTAG﹕ authenticator class says that 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 ));
}
最佳答案
注入(inject)值意味着您不自己分配值。这表示,
@Inject
SessionKeyExchangerService sessionKeyExchangerService;
// then in onCreate() after the injection
sessionKeyExchangerService = savedInstanceState.getParcelable(SESSION_KEY_PARCEL);
不是你想做的。
如果您的 SessionKeyExchangerService
依赖于某些已保存的状态,则您必须将其传递到您的模块中。
AppModule
似乎是提供 SessionKeyExchangerService
的错误位置。你应该外包给一些 SessionModule
然后你可以交换,我认为是 well explained here .在此示例中,UserModule 生命周期由应用而非 Dagger 管理。
通过为模块提供构造函数,您可以从 savedInstanceState
传入 Parcelable
状态。
在不了解您的整个项目的情况下,我认为您可以大大降低复杂性并且可能不应该在 Activity 中保存状态,而是使用 SharedPreferences
或普通文件。这也将消除使用 Activity 状态维护模块生命周期的需要。
关于android - Dagger 2 在 Activity 停止时保存和恢复状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33587542/