5

Android Jetpack之Room

 3 years ago
source link: https://blog.csdn.net/mingyunxiaohai/article/details/89429969
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Android Jetpack之Room

chsmy2018 2019-04-21 11:11:17 861
分类专栏: jetpack

Room是在Sqlite数据的一个抽象层,拥有更强大的数据访问能力。

导入依赖:

    def room_version = "2.1.0-alpha06"
    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
    
     // kotlin扩展和协程支持
    implementation "androidx.room:room-ktx:$room_version"
    //RxJava 支持库
    implementation "androidx.room:room-rxjava2:$room_version"
    // 可选 - Guava 的支持库
    implementation "androidx.room:room-guava:$room_version"

下面开始使用

第一步创建实体类

假如我们有一个用户表,每个用户的实体就是表中的一列

@Entity
public class User {

    @PrimaryKey
    @NonNull
    @ColumnInfo(name = "id_")
    public int id;

    public String name;
    public String password;
    public String school;

}
  • @Entity: 代表一个表中的实体,默认类名就是表名,如果不想使用类名作为表名,可以给注解添加表名字段@Entity(tableName = "user_table")
  • @PrimaryKey: 每个实体都需要自己的主键
  • @NonNull 表示字段,方法,参数返回值不能为空
  • @ColumnInfo(name = “lastname”) 如果希望表中字段名跟类中的成员变量名不同,添加此字段指明

第二步创建DAO

  • DAO是数据访问对象,指定SQL查询,并让他与方法调用相关联。
  • DAO必须是一个接口或者抽象类。
  • 默认情况下,所有的查询都必须在单独的线程中执行
@Dao
public interface UserDao {
    @Insert
    void insert(User user);

    @Query("select * from user")
    List<User> getUserList();

    @Query("delete from user")
    void deleteAll();
    
     @Update
    void updateUsers(User... users);
}
  • 创建一个接口UserDao
  • 给它添加注解@Dao,表名它是Room的一个查询类
  • 声明一个插入用户的方法insert,并给它添加注解@Insert,不用提供任何SQL语句
  • 声明一个删除全部的方法,deleteAll(),删除方法没有便捷方法,需要使用@Query注解,并且提供相应的SQL语句delete from user
  • 声明一个getUserList方法来查询所有的用户,这个也没有便捷方法,,需要使用@Query注解,并且提供相应的SQL语句select * from user

第三步添加Database

Room是SQLite数据库之上的数据库层,可以让我们轻松的使用系统原始API:SQLiteOpenHelper

@Database(entities = {User.class},version = 1)
public abstract class UserRoomDatabase extends RoomDatabase {
   public abstract UserDao userDao();

   public static UserRoomDatabase instance;

   public static UserRoomDatabase getInstance(Context context){
       if(instance == null){
           synchronized (UserRoomDatabase.class){
               if(instance == null){
                   instance = Room.databaseBuilder(context.getApplicationContext(),UserRoomDatabase.class
                   ,"user_database").build();
               }
           }
       }
       return instance;
   }
}
  • 创建一个抽象类继承自RoomDatabase
  • 给他添加一个注解@Database表名它是一个数据库,注解有两个参数第一个是数据库的实体,它是一个数组,可以传多个,当数据库创建的时候,会默认给创建好对应的表,第二个参数是数据库的版本号
  • 定义跟数据库一起使用的相关的DAO类
  • 创建一个UserRoomDatabase的单例,防止同时打开多个数据库的实例
  • 使用Room提供的数据库构建器来创建该实例,第一个参数application,第二个参数当前数据库的实体类,第三个参数数据库的名字

第四步开始使用

前面三步主要步骤写完了,现在就可以开始使用了,使用的时候,为了让Activity中代码简洁,创建一个UserRepository类来管理这个数据库

public class UserRepository {

    private UserDao mUserDao;

    private List<User> allUser;

    public UserRepository(Application application) {
        //UserRoomDatabase db = UserRoomDatabase.getInstance(application);
        //mUserDao = db.userDao();
        //allUser = mUserDao.getUserList();
        //使用ViweModel可以直接使用上面注释了的
        new InitThread(application).start();
    }

    public List<User> getAllUser() {
        return allUser;
    }

    public void deleteAll(){
        new DeleteAsyncTask(mUserDao).execute();
    }
    
    public void update(User user){
       new UpdateAsyncTask(mUserDao).execute(user);
    }

    public void insert(User user){
     new InsertAsyncTask(mUserDao).execute(user);
    }

    private  class InitThread extends Thread{
        Application application;
        InitThread(Application application){
            this.application = application;
        }
        @Override
        public void run() {
            UserRoomDatabase db = UserRoomDatabase.getInstance(application);
            mUserDao = db.userDao();
            allUser = mUserDao.getUserList();
        }
    }
    //更新
    private static class UpdateAsyncTask extends AsyncTask<User, Void, Void> {

        private UserDao mAsyncTaskDao;

        UpdateAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final User... params) {
            mAsyncTaskDao.updateUsers(params[0]);
            return null;
        }
    }
    //插入
    private static class InsertAsyncTask extends AsyncTask<User, Void, Void> {

        private UserDao mAsyncTaskDao;

        InsertAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final User... params) {
            mAsyncTaskDao.insert(params[0]);
            return null;
        }
    }
    //删除
    private static class DeleteAsyncTask extends AsyncTask<Void, Void, Void> {

        private UserDao mAsyncTaskDao;

        DeleteAsyncTask(UserDao dao) {
            mAsyncTaskDao = dao;
        }
        @Override
        protected Void doInBackground(Void... voids) {
            mAsyncTaskDao.deleteAll();
            return null;
        }
    }
}

这个类的作用就是初始化数据库和响应的DAO类,对外提供插入、查询等方法。

注意:数据库的创建,表的插入和删除操作,Room会强制要求在非UI线程中使用,否则会崩溃。

在Activity中初始化UserRepository之后,就可以进行相关的操作了

使用LiveData和ViewModel

当数据变化的时候,LiveData可以观察到数据的变化,可以让我们实时更新UI

ViewModel可以更好的保存Activity中的数据,比如屏幕旋转的时候数据不会丢失

ViewModel与Room和LiveData一起工作可以替换以前的loader。ViewModel确保数据在设备配置更改后仍然存在。当数据库发生更改时,Room会通LiveData,而LiveData反过来又用修改后的数据更的UI。

将DAO中的查询更改为下面

@Query("select * from user")
    LiveData<List<User>> getUserList();

然后创建ViewModel

public class UserViewModel extends AndroidViewModel {
    private LiveData<List<User>> mUsers;
    private UserRepository mRepository;

    public UserViewModel(Application application) {
        super(application);
        mRepository = new UserRepository(application);
        mUsers =  mRepository.getAllUser();
    }

    public LiveData<List<User>> getUsers(){
        return mUsers;
    }

    public void insertUser(User user){
        mRepository.insert(user);
    }

    public void deleteAll(){
        mRepository.deleteAll();
    }
    
    public void update(User user){
        mRepository.update(user);
    }
}

我们单独使用LiveData的时候,都是使用MutableLiveData,当与Room一块使用的时候只能使用LiveData。

Activity中使用

public class RoomActivity extends AppCompatActivity {
    List<User> mUsers = new ArrayList<>();
    UserRepository mRepository;
    MyAdapter mAdapter;
    int index = 0;
    private UserViewModel mViewModel;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_room);
//        mRepository = new UserRepository(getApplication());
//        mUsers = new ArrayList<>();
        RecyclerView recyclerView = findViewById(R.id.recycleview);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(manager);
        mAdapter = new MyAdapter(mUsers,this);
        recyclerView.setAdapter(mAdapter);

        mViewModel = ViewModelProviders.of(this).get(UserViewModel.class);

        mViewModel.getUsers().observe(this, new Observer<List<User>>() {
            @Override
            public void onChanged(List<User> users) {
                mUsers.clear();
                mUsers.addAll(users);
                mAdapter.notifyDataSetChanged();
            }
        });

    }

    public void insert(View view) {
        User user = new User();
        user.id =index;
        user.name = "张三"+ Math.random()*100;
        user.school = "北大"+ Math.random()*100;
        user.password = "123"+ Math.random()*100;
//        mRepository.insert(user);
        mViewModel.insertUser(user);
        index++;
    }

    public void query(View view) {
//        List<User> allUser = mRepository.getAllUser();
//        mUsers.addAll(allUser);
//        mAdapter.notifyDataSetChanged();
    }

    public void deleteAll(View view) {
        mViewModel.deleteAll();
    }
    
    public void update(View view) {
        User user = new User();
        user.id =0;
        user.name = "张三"+ Math.random()*100;
        user.school = "北大"+ Math.random()*100;
        user.password = "123"+ Math.random()*100;
        mViewModel.update(user);
    }
}

数据库升级

当数据库中的表或者表中的字段有变化的时候,我们需要升级数据的版本,这个时候,我们不希望现在数据库中的数据丢失

Room提供了相应的类(Migration)来完成数据库的迁移,需要传入一个旧版本和新版本,比如现在在user表中新加一个age字段

  1. 在User类中新加一个字段
public int age;
  1. 编写Migration类,编写sql更改数据库
  private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(SupportSQLiteDatabase database) {
            database.execSQL("alter table user add age INTEGER NOT NULL default 0");
        }
    };
  1. 更改数据库的版本由1变成2
@Database(entities = {User.class},version = 2,exportSchema = false)
public abstract class UserRoomDatabase extends RoomDatabase {}
  1. 更改数据库的创建方法
instance = Room.databaseBuilder(context.getApplicationContext(),UserRoomDatabase.class
                   ,"user_database")
                           .addMigrations(MIGRATION_1_2)
                           .build();

然后重新运行程序就可以看到age字段已经加到表里了。

addMigrations方法,里面可以接收多个参数,比如现在只是编写了版本1-2的升级方法MIGRATION_1_2,假如我们还有2-3版本的还可以编写一个MIGRATION_2_3,添加到后面。

更新数据库的版本


OK,到这里Room的简单使用就完成啦。下面来看看它的源码吧

前面我们知道数据库的创建是从Room.databaseBuilder(...).build();方法开始,很明显看出来这是通过建造者模式创建出来的。传入一些参数到RoomDatabase.Builder中,最终的创建方法肯定就是在build中。

      public T build() {
      
           ......

            if (mFactory == null) {
                mFactory = new FrameworkSQLiteOpenHelperFactory();
            }
            //数据库配置
            DatabaseConfiguration configuration =
                    new DatabaseConfiguration(
                            mContext,
                            mName,
                            mFactory,
                            mMigrationContainer,
                            mCallbacks,
                            mAllowMainThreadQueries,
                            mJournalMode.resolve(mContext),
                            mQueryExecutor,
                            mTransactionExecutor,
                            mMultiInstanceInvalidation,
                            mRequireMigration,
                            mAllowDestructiveMigrationOnDowngrade,
                            mMigrationsNotRequiredFrom);
            //前面创建的UserRoomDatabase是个抽象类,编译期间会生成对应的实现类UserRoomDatabase_Impl,获取UserRoomDatabase的实现类
            T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
            //初始化数据库
            db.init(configuration);
            return db;
        }
    }

创建了一个SQLiteOpenHelper的工厂类FrameworkSQLiteOpenHelperFactory

public final class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {
    @Override
    public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
        return new FrameworkSQLiteOpenHelper(
                configuration.context, configuration.name, configuration.callback);
    }
}

这个工厂方法可以创建一个FrameworkSQLiteOpenHelper,它是SupportSQLiteOpenHelper接口的实现类。

class FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
    private final OpenHelper mDelegate;

    FrameworkSQLiteOpenHelper(Context context, String name,
            Callback callback) {
        mDelegate = createDelegate(context, name, callback);
    }

可以看到在其构造方法中创建了一个代理类OpenHelper

    static class OpenHelper extends SQLiteOpenHelper {......}

OpenHelper继承自系统的SQLiteOpenHelper,它用来监听数据库的创建(onCreate)升级(onUpgrade)等操作。然后回调给RoomOpenHelper来处理。

回到build()方法中,将数据库的配置封装到DatabaseConfiguration中,然后获取我们之前写的抽象类UserRoomDatabase的一个实现类,这个实现类是注解器在编译期间自动创建的。

位置在:build->generated->source->apt->debug->你的包名中找到。最后初始化数据库。怎么创建的可以去查一下编译时注解的原理。

    static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {
        //包名
        final String fullPackage = klass.getPackage().getName();
        //全名
        String name = klass.getCanonicalName();
        final String postPackageName = fullPackage.isEmpty()
                ? name
                : (name.substring(fullPackage.length() + 1));
        //拼成UserRoomDatabase_Impl
        final String implName = postPackageName.replace('.', '_') + suffix;
        //noinspection TryWithIdenticalCatches
        try {
        //通过反射找到生成的类,然后实例化
            @SuppressWarnings("unchecked")
            final Class<T> aClass = (Class<T>) Class.forName(
                    fullPackage.isEmpty() ? implName : fullPackage + "." + implName);
            return aClass.newInstance();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("cannot find implementation for "
                    + klass.getCanonicalName() + ". " + implName + " does not exist");
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Cannot access the constructor"
                    + klass.getCanonicalName());
        } catch (InstantiationException e) {
            throw new RuntimeException("Failed to create an instance of "
                    + klass.getCanonicalName());
        }
    }

上面的方法就是根据我们传入的数据库的类名,拼接出Room编译器给自动生成的实现类的名字,然后通过反射找到这个类并实例化返回。

下面看一下这个自动生成的类UserRoomDatabase_Impl

public final class UserRoomDatabase_Impl extends UserRoomDatabase {
  private volatile UserDao _userDao;

  @Override
  protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
    final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(2) {
      @Override
      public void createAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`id_` INTEGER NOT NULL, `name` TEXT, `password` TEXT, `school` TEXT, `age` INTEGER NOT NULL, PRIMARY KEY(`id_`))");
        _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
        _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"c59ead1e532b11ea2062c3f5e814a66b\")");
      }

      @Override
      public void dropAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("DROP TABLE IF EXISTS `User`");
      }

      @Override
      protected void onCreate(SupportSQLiteDatabase _db) {
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onCreate(_db);
          }
        }
      }

      @Override
      public void onOpen(SupportSQLiteDatabase _db) {
        mDatabase = _db;
        internalInitInvalidationTracker(_db);
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onOpen(_db);
          }
        }
      }

      @Override
      public void onPreMigrate(SupportSQLiteDatabase _db) {
        DBUtil.dropFtsSyncTriggers(_db);
      }

      @Override
      public void onPostMigrate(SupportSQLiteDatabase _db) {
      }

      @Override
      protected void validateMigration(SupportSQLiteDatabase _db) {
        final HashMap<String, TableInfo.Column> _columnsUser = new HashMap<String, TableInfo.Column>(5);
        _columnsUser.put("id_", new TableInfo.Column("id_", "INTEGER", true, 1));
        _columnsUser.put("name", new TableInfo.Column("name", "TEXT", false, 0));
        _columnsUser.put("password", new TableInfo.Column("password", "TEXT", false, 0));
        _columnsUser.put("school", new TableInfo.Column("school", "TEXT", false, 0));
        _columnsUser.put("age", new TableInfo.Column("age", "INTEGER", true, 0));
        final HashSet<TableInfo.ForeignKey> _foreignKeysUser = new HashSet<TableInfo.ForeignKey>(0);
        final HashSet<TableInfo.Index> _indicesUser = new HashSet<TableInfo.Index>(0);
        final TableInfo _infoUser = new TableInfo("User", _columnsUser, _foreignKeysUser, _indicesUser);
        final TableInfo _existingUser = TableInfo.read(_db, "User");
        if (! _infoUser.equals(_existingUser)) {
          throw new IllegalStateException("Migration didn't properly handle User(com.chs.androiddailytext.jetpack.User).\n"
                  + " Expected:\n" + _infoUser + "\n"
                  + " Found:\n" + _existingUser);
        }
      }
    }, "c59ead1e532b11ea2062c3f5e814a66b", "c0809d515e95fc9eec52ad8880ec6aae");
    final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
        .name(configuration.name)
        .callback(_openCallback)
        .build();
    final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
    return _helper;
  }

  @Override
  protected InvalidationTracker createInvalidationTracker() {
    final HashMap<String, String> _shadowTablesMap = new HashMap<String, String>(0);
    HashMap<String, Set<String>> _viewTables = new HashMap<String, Set<String>>(0);
    return new InvalidationTracker(this, _shadowTablesMap, _viewTables, "User");
  }

  @Override
  public void clearAllTables() {
    super.assertNotMainThread();
    final SupportSQLiteDatabase _db = super.getOpenHelper().getWritableDatabase();
    try {
      super.beginTransaction();
      _db.execSQL("DELETE FROM `User`");
      super.setTransactionSuccessful();
    } finally {
      super.endTransaction();
      _db.query("PRAGMA wal_checkpoint(FULL)").close();
      if (!_db.inTransaction()) {
        _db.execSQL("VACUUM");
      }
    }
  }

  @Override
  public UserDao userDao() {
    if (_userDao != null) {
      return _userDao;
    } else {
      synchronized(this) {
        if(_userDao == null) {
          _userDao = new UserDao_Impl(this);
        }
        return _userDao;
      }
    }
  }
}
  • createOpenHelper方法,创建SupportSQLiteOpenHelper的实现类FrameworkSQLiteOpenHelper,前面我们知道他的构造方法中创建了一个代理类OpenHelper它继承自系统的SQLiteOpenHelper,这个就是我们如果不使用Room,而是自己使用系统提供的类操作数据库的时候需要创建的类,这里Room帮我们创建好了,这个方法是在前面build()方法中的 db.init(configuration)中调用的
  • createOpenHelper方法中创建了SupportSQLiteOpenHelper.Callback这个回调,并实现它的回调方法从代码中看到它是一个RoomOpenHelper。
  • OpenHelper监听系统回调,监听到之后会回调RoomOpenHelper的相关方法,RoomOpenHelper又会回调UserRoomDatabase_Impl中的相关方法。
  • onCreate()中Sql语句创建user表和room_master_table表,dropAllTables方法删除数据库,validateMigration方法实现数据库升级
  • userDao()方法创建UserDao_Impl的实例,这个UserDao_Impl也是注解处理器给我们自动生成的,这里面就是我们定义的UserDao中增删改查的真正实现的地方。

然后在看build()方法中的init方法

 public void init(@NonNull DatabaseConfiguration configuration) {
        mOpenHelper = createOpenHelper(configuration);
        boolean wal = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING;
            mOpenHelper.setWriteAheadLoggingEnabled(wal);
        }
        mCallbacks = configuration.callbacks;
        mQueryExecutor = configuration.queryExecutor;
        mTransactionExecutor = new TransactionExecutor(configuration.transactionExecutor);
        mAllowMainThreadQueries = configuration.allowMainThreadQueries;
        mWriteAheadLoggingEnabled = wal;
        if (configuration.multiInstanceInvalidation) {
            mInvalidationTracker.startMultiInstanceInvalidation(configuration.context,
                    configuration.name);
        }
    }
  • createOpenHelper(configuration)就是调用了UserRoomDatabase_Impl中的createOpenHelper方法。
  • mQueryExecutor 和 mTransactionExecutor 是两个线程池,查询和事物的线程池。这就是为啥前面例子中我们的查询方法不用自己放到非UI线程中执行,而插入和更新方法却需要自己创建子线程执行了。

下面来看看升级的方法,前面我们知道OpenHelper这个代理类继承了系统的SQLiteOpenHelper,会监听系统的数据库相关事件,我们找到它中的升级方法

 public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
            mMigrated = true;
            mCallback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
        }

mCallback就是我们在UserRoomDatabase_Impl中创建的RoomOpenHelper一路传进来的

  public void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
        boolean migrated = false;
        if (mConfiguration != null) {
        //根据版本号查找对应的migrations
            List<Migration> migrations = mConfiguration.migrationContainer.findMigrationPath(
                    oldVersion, newVersion);
            if (migrations != null) {
                //迁移之前的初始化工作
                mDelegate.onPreMigrate(db);
                //循环执行我们写的sql
                for (Migration migration : migrations) {
                    migration.migrate(db);
                }
                //验证升级结果
                mDelegate.validateMigration(db);
                mDelegate.onPostMigrate(db);
                updateIdentity(db);
                migrated = true;
            }
        }
        //如果没有执行我们的sql
        if (!migrated) {
            if (mConfiguration != null
                    && !mConfiguration.isMigrationRequired(oldVersion, newVersion)) {
                //删除清空表
                mDelegate.dropAllTables(db);
                mDelegate.createAllTables(db);
            } else {
                throw new IllegalStateException("A migration from " + oldVersion + " to "
                        + newVersion + " was required but not found. Please provide the "
                        + "necessary Migration path via "
                        + "RoomDatabase.Builder.addMigration(Migration ...) or allow for "
                        + "destructive migrations via one of the "
                        + "RoomDatabase.Builder.fallbackToDestructiveMigration* methods.");
            }
        }
    }

这里面的mDelegate就是我们在UserRoomDatabase_Impl中new出来的RoomOpenHelper.Delegate,并实现了它里面的方法,所以上面代码中调用Delegate最终都会到达UserRoomDatabase_Impl中的相关方法执行。

findMigrationPath方法根据版本号找到相应的migrations,前面使用中我们知道migrations中封装了我们升级数据库的sql语句。

循环执行我们的migrations,执行我们写的升级的sql语句,执行完之后验证是否升级成功。

如果没有执行找到需要执行的migrations ,并且mConfiguration.isMigrationRequired(oldVersion, newVersion)为false,就会清空数据库中所有的表。

    public boolean isMigrationRequired(int fromVersion, int toVersion) {
        final boolean isDowngrade = fromVersion > toVersion;
        if (isDowngrade && allowDestructiveMigrationOnDowngrade) {
            return false;
        }
        ......
    }

可以看到当旧版本大于新版本的时候或者allowDestructiveMigrationOnDowngrade为true的时候返回false。

allowDestructiveMigrationOnDowngrade这个标志位可以在数据库创建的时候指定

Room.databaseBuilder(context.getApplicationContext(),UserRoomDatabase.class
                   ,"user_database")
                           .fallbackToDestructiveMigration()
                           .build();

加上它之后升级就会清空数据库中以前的数据。一般情况下我们都是希望保留数据的,所以需要些我们自己的Migration类,定义升级的sql。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK