首页 > 解决方案 > 通用迁移

问题描述

我喜欢在 Android 应用程序中将各种东西从一个版本迁移到另一个版本。我的具体迁移都准备好了并且工作正常。我迁移 sharedPrefences,压缩图像多一点等等。

但我想不出处理:

  1. 每次迁移只优雅地运行一次。(到目前为止,它是用 shared.-pref MIGRATION_v1_DONE 完成的)。
  2. 不要为新安装运行迁移。

我在这里找到了这个项目。这很好,因为它只运行一次迁移,如果我退出异常,迁移将再次运行,因为它还没有完成。

但是这个项目也将为新安装运行迁移。所以我需要为每次迁移添加检查和更多检查。非常容易出错。我想使用该库但不用于新安装。

我在想类似的东西:

  1. 版本 1 到 2 的迁移类文件。
  2. 新安装已经是版本 2,不会被迁移。
  3. 将来版本 2 到 3 的类文件。
  4. 新安装已经是版本 3,不会迁移。

标签: androidmigrationsharedpreferences

解决方案


引入一个 MigrationFactory 类,并且对于每个迁移,它都是从具有#migrate 功能的抽象类扩展而来的类。

整个迁移通过读取和写入BuildConfig.VERSION_CODE常量来进行。在第一次运行时(在引入 MigrationFactory 时进行新安装),此值为 0。循环从 0 迭代到当前 VERSION_CODE,并且当迭代与案例匹配时,切换案例开始运行。

在第一次运行 case 0 匹配。在我的构造中,这会检查 sharedPref 值是否存在。如果不是这种情况,应用程序是新安装的并且不需要迁移,int i 将设置为当前 VERSION_CODE,在 break 后切换 case,for 循环离开了我的 break。如果找到 sharedPref(应用程序已安装并且刚刚更新)循环连续 1、2、3... ohh 54 - 案例匹配并运行 V54Migration#migrate。

假设 BuildConfig.VERSION_CODE 当前为 72。 V72Migration 未运行。它将在 BuildConfig.VERSION_CODE = 73 上运行!在未来的某个版本中,可能需要在 VERSION_CODE = 77 上进行另一次迁移。这将在 VERSION_CODE 78 的版本上运行。

对于具有非常旧版本的应用程序(更新前的 VERSION_CODE = 10)并且现在应用程序是 VERSION_CODE 75 的人,将运行迁移 54、71 和 72

public class MigrationFactory {

private static final String CURRENT_VERSIONCODE = "current_versioncode";
// ...

private void setVersionCode(int versionCode) {
    PrefManager.with(mContext).save(CURRENT_VERSIONCODE, versionCode);
}

public boolean isMigrationNeeded() {
    return getVersionCode() < BuildConfig.VERSION_CODE;
}

private int getVersionCode() {
    //Empty during first run. Will return 0 instead.
    return PrefManager.with(mContext).getInt(CURRENT_VERSIONCODE, 0);
}

public void createMigration() {
    for (int i = getVersionCode(); i < BuildConfig.VERSION_CODE; i++) {
        switch (i) {
            case 0:
                if (!mContext.getSharedPreferences(mContext.getPackageName())
                     .contains("a string only existent in an already installed version")})) {
                    Log.d(MainApplication.getTAG(this.getClass()), "I am a V0_NewInstall");
                    //if new install set i to current VERSION_CODE, no
                    //migrations needed in that case.
                    i = BuildConfig.VERSION_CODE;
                    //Now exist out the loop and switch case.
                    break;
                }
                break;
            case 54:
                new V54_CropJPGAvatarImages(mContext).migrate();
                break;
            case 71:
                new V71_CompressJPG(mContext).migrate();
                break;
            case 72:
                new V72_SetWhatever(mContext).migrate();
                break;
            case 77:
                break;
        }
    }
    setVersionCode(BuildConfig.VERSION_CODE);
}
}

我在我的 MainApplication#onCreate 中调用这个类:

MigrationFactory migrationFactory = MigrationFactory.getInstance(this);
    if (migrationFactory.isMigrationNeeded())
        migrationFactory.createMigration();

推荐阅读