活动停止时匕首2保存并恢复状态

时间:2015-11-07 20:41:39

标签: android state activity-lifecycle dagger-2

我陷入了僵局。我使用Dagger 2进行依赖注入,但是当应用程序进入后台时我失去了状态。这是场景:应用程序启动并创建依赖项。只要应用程序停留在前台,所有功能都可以完美运行。但是,有一种情况是应用程序必须进入后台。当它返回时,存储在我注入的一个类中的值将丢失。

对于我没有依赖自己的注入类,一切似乎都恢复正常。但是,有一个注入类具有注入依赖关系,这是一个无法恢复的类。以下是我的设置方法:

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);
    }
}

然后当我去注入这些依赖项时,我这样做:

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注入类的状态。我很乐意分享更多代码,但这是必不可少的想法。

感谢您的帮助。

修改 假设我上面所做的就是好的,让我继续讨论如何保存和检索存储在这些注入对象中的值。这将表明某处存在问题。

当我进入后台,然后回来时,我可以看到我得到一个新的PID。我还可以看到我能够在LoginActivity类中正确地存储和检索注入的值。但是,其他也引用注入值的类现在具有不同的值,这意味着它们的引用是针对不同的内存位置,对吧?

我最好的猜测是我在哪里出错了是在LoginActivity onCreate中我从保存的地块恢复sessionKeyExchangerService值。我认为我正在创建在应用程序中无法识别为注入依赖项的新值,但我不知道为什么这是错误的或如何解决它。

此代码也在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的引用具有不同的会话密钥值的方式如何:

  

1398-1398 / com.mysite.myapp D / MYTAG:保存实例状态
  1398-1398 / com.mysite.myapp D / MYTAG:保存会话密钥:   93Zuy8B3eos + eCfBQk9ErA ==
1398-1398 / com.mysite.myapp D / MYTAG:on   停止
3562-3562 / com.mysite.myapp D / MYTAG:检索到的会话密钥   on create:93Zuy8B3eos + eCfBQk9ErA ==
3562-3562 / com.mysite.myapp   D / MYTAG:开始时3562-3562 / com.mysite.myapp D / MYTAG:会话密钥   在恢复状态下检索:93Zuy8B3eos + eCfBQk9ErA ==
  3562-3562 / com.mysite.myapp D / MYTAG:authenticator类说的   会话密钥是: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 ));
}

1 个答案:

答案 0 :(得分:1)

注入值意味着您不自己分配值。这说,

inner_func

不是你想要做的。

如果您的@Inject SessionKeyExchangerService sessionKeyExchangerService; // then in onCreate() after the injection sessionKeyExchangerService = savedInstanceState.getParcelable(SESSION_KEY_PARCEL); 取决于某些已保存的状态,则必须将其传递到您的模块中。

SessionKeyExchangerService似乎是提供AppModule的错误位置。你可能应该外包给一些你可以交换的SessionKeyExchangerService,我认为是well explained here。在此示例中,UserModule生命周期由应用程序管理,而不是匕首。

通过为模块提供构造函数,您可以从SessionModule传递Parcelable状态。

在不了解整个项目的情况下,我认为您可以大大降低复杂性,可能不应该在活动中保存状态,而是使用savedInstanceState或普通文件。这也可以消除维护模块生命周期与活动状态的需要。