官网链接
开始使用
首先依赖库
def room_version = "2.2.6"
//注解
implementation "androidx.room:room-runtime:$room_version"
//注解处理器
annotationProcessor "androidx.room:room-compiler:$room_version"
定义实体类
package com.suyong.myroom.bean;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
//所有的成员变量(不被@Ignore修饰的都会创建表字段)
//由此看出不仅有注解加反射的模式还有orm(对象关系映射型)结构。
@Entity
public class User {
//自增主键
@PrimaryKey(autoGenerate = true)
@NonNull
public int uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
//不需要创建该字段
@Ignore
public String nickName;
}
定义DAO类
//对表进行修改数据的类
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(User... users);
@Delete
void delete(User user);
}
定义创建数据库的类
//记住必须是抽象类
//必须继承RoomDatabase
//必须定义要创建的抽象的类
@Database(entities = {User.class}, version = 1)
public abstract class AbstractAppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
愉快的使用了。
//创建临时数据库
//进程杀死就没了
Room.inMemoryDatabaseBuilder(getApplicationContext(),AbstractAppDatabase.class);
//永久数据库
//这里返回的其实通过apt技术生成的AbstractAppDatabase_Impl对象
AbstractAppDatabase db = Room.databaseBuilder(getApplicationContext(),
AbstractAppDatabase.class, "MyDatabase")
//是否运行再主线程做数据库操作
.allowMainThreadQueries()
//回调
.addCallback(new RoomDatabase.Callback() {
@Override
public void onCreate(@NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
}
@Override
public void onOpen(@NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
@Override
public void onDestructiveMigration(@NonNull SupportSQLiteDatabase db) {
super.onDestructiveMigration(db);
}
})
//设置查询线程池
.setQueryExecutor(executor)
//实现加密存储,默认不加密存储
.openHelperFactory(new SupportSQLiteOpenHelper.Factory() {
@Override
public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
return null;
}
})
//数据库升级
.addMigrations(new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
}
})
.build();
UserDao userDao = db.userDao();
List<User> users = userDao.getAll();
接下来我们从使用的角度来查看源码(省去花里胡哨的设置,直接构建)
AbstractAppDatabase db = Room.databaseBuilder(getApplicationContext(),
AbstractAppDatabase.class, "MyDatabase").build();
@NonNull
public T build() {
//noinspection ConstantConditions
if (mContext == null) {
throw new IllegalArgumentException("Cannot provide null context for the database.");
}
//noinspection ConstantConditions
if (mDatabaseClass == null) {
throw new IllegalArgumentException("Must provide an abstract class that"
+ " extends RoomDatabase");
}
if (mQueryExecutor == null && mTransactionExecutor == null) {
mQueryExecutor = mTransactionExecutor = ArchTaskExecutor.getIOThreadExecutor();
} else if (mQueryExecutor != null && mTransactionExecutor == null) {
mTransactionExecutor = mQueryExecutor;
} else if (mQueryExecutor == null && mTransactionExecutor != null) {
mQueryExecutor = mTransactionExecutor;
}
if (mMigrationStartAndEndVersions != null && mMigrationsNotRequiredFrom != null) {
for (Integer version : mMigrationStartAndEndVersions) {
if (mMigrationsNotRequiredFrom.contains(version)) {
throw new IllegalArgumentException(
"Inconsistency detected. A Migration was supplied to "
+ "addMigration(Migration... migrations) that has a start "
+ "or end version equal to a start version supplied to "
+ "fallbackToDestructiveMigrationFrom(int... "
+ "startVersions). Start version: "
+ version);
}
}
}
if (mFactory == null) {
mFactory = new FrameworkSQLiteOpenHelperFactory();
}
if (mCopyFromAssetPath != null || mCopyFromFile != null) {
if (mName == null) {
throw new IllegalArgumentException("Cannot create from asset or file for an "
+ "in-memory database.");
}
if (mCopyFromAssetPath != null && mCopyFromFile != null) {
throw new IllegalArgumentException("Both createFromAsset() and "
+ "createFromFile() was called on this Builder but the database can "
+ "only be created using one of the two configurations.");
}
mFactory = new SQLiteCopyOpenHelperFactory(mCopyFromAssetPath, mCopyFromFile,
mFactory);
}
DatabaseConfiguration configuration =
new DatabaseConfiguration(
mContext,
mName,
mFactory,
mMigrationContainer,
mCallbacks,
mAllowMainThreadQueries,
mJournalMode.resolve(mContext),
mQueryExecutor,
mTransactionExecutor,
mMultiInstanceInvalidation,
mRequireMigration,
mAllowDestructiveMigrationOnDowngrade,
mMigrationsNotRequiredFrom,
mCopyFromAssetPath,
mCopyFromFile);
T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
db.init(configuration);
return db;
}
很明显这个额build方法通过getGeneratedImplementation
返回了一个对象。
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));
final String implName = postPackageName.replace('.', '_') + suffix;
//noinspection TryWithIdenticalCatches
try {
@SuppressWarnings("unchecked")
//通过反射的方式创建一个对象(以_Impl为后缀)
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());
}
}
所以AbstractAppDatabase db = Room.databaseBuilder(getApplicationContext(), AbstractAppDatabase.class, "MyDatabase").build()
db对象其实是AbstractAppDatabase_Impl
,所以db.userDao();
就是AbstractAppDatabase_Impl.userDao()
。
@Override
public UserDao userDao() {
if (_userDao != null) {
return _userDao;
} else {
synchronized(this) {
if(_userDao == null) {
//可以看到这里创建了一个UserDao_Impl类
_userDao = new UserDao_Impl(this);
}
return _userDao;
}
}
}
所以userDao.getAll();
就是UserDao_Impl.getAll();
public final class UserDao_Impl implements UserDao {
......
//具体查询数据库数据的实现类
@Override
public List<User> getAll() {
final String _sql = "SELECT * FROM user";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
__db.assertNotSuspendingTransaction();
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
final int _cursorIndexOfFirstName = CursorUtil.getColumnIndexOrThrow(_cursor, "first_name");
final int _cursorIndexOfLastName = CursorUtil.getColumnIndexOrThrow(_cursor, "last_name");
final List<User> _result = new ArrayList<User>(_cursor.getCount());
while(_cursor.moveToNext()) {
final User _item;
_item = new User();
_item.uid = _cursor.getInt(_cursorIndexOfUid);
_item.firstName = _cursor.getString(_cursorIndexOfFirstName);
_item.lastName = _cursor.getString(_cursorIndexOfLastName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
......
}
到这里就结束了,Room就是采用注解的方式,通过APT(编译时技术)生成了我们所需要的实现类(以_Impl结尾的)来实现我们具体的业务逻辑。
APT 技术我也出过一个案例,有兴趣的可以看一下。
Android编译时技术,仿照ButterKnife,实现自己的自动注入框架