前言:
ROOM是JetPack框架中的数据库操作部分,是对Android数据库SQLite的封装。使用户能够更方便的对数据库进行操作。
由于AndroidX和kotlin的原因,所以ROOM在版本上分为support版本和AndroidX版本,在语言上分为kotlin和java版本。本系列脱胎于实际开发经验,所以侧重于support版本和AndroidX版本,主要侧重于AndroidX版本。因为Jetpack更新后没有往support上面更新。所以有些功能在support上面用不了。所以针对support版本不给出具体示例,只是简要提出问题所在。在support中不能包含androidx相关代码,否则会出现依赖冲突
使用要点:
1、ROOM数据库无法单独使用,最少也要与ViewModel进行配套使用。因为没有办法在ViewModel之外的地方获取ROOM相关操作类
2、ROOM所有操作均在子线程中操作,所以可以用LiveData或者RxJava进行,配套转换。这里使用LiveData。
3、本示例是基于Google的框架示范进行编写的
下面开始正式的代码编写,本文编写一个群组的数据库,主要实现用户和群组直接的关联,整个过程是从简单到复杂的编写过程
AndroidX 版本的 build.gradle
android{
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies{
/**
* ROOM数据库
* */
annotationProcessor 'androidx.room:room-compiler:2.2.5'
implementation 'androidx.room:room-runtime:2.2.5'
androidTestImplementation "androidx.room:room-testing:2.2.5"
// Lifecycle components
//拓展库一定要有,负责new ViewModelProvider(this)创建ViewModel时候会报参数数量不对的错
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
// annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.2.0"
// implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
}
注意 implementation 'com.google.android.material:material:1.1.0'
,这个依赖里面包含了ROOM、Lifecycle、LiveData、ViewModel。所以当集成这个依赖时候,其他的不用集成也没事,不过里面的版本可能不是自己想要的,有时候也会产生依赖冲突。
support版本的 build.gradle
android{
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies{
/**
* ROOM数据库
* */
// annotationProcessor 'androidx.room:room-compiler:2.2.5'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
// implementation 'androidx.room:room-runtime:2.2.5'
implementation 'android.arch.persistence.room:runtime:1.1.1'
androidTestImplementation "androidx.room:room-testing:2.2.5"
// Lifecycle components
// implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
api "android.arch.lifecycle:extensions:1.1.1"
implementation "android.arch.lifecycle:viewmodel:1.1.1"
implementation "android.arch.lifecycle:livedata:1.1.1"
implementation "com.android.support:support-annotations:28.0.0"
}
-
因为要使用ViewModel,所以在support版本中要使用
api "android.arch.lifecycle:extensions:1.1.1"
因为这个依赖里面包含了ViewModelProviders类,写法上会简单很多,该写法可以在Activity和Fragment中使用,而不需要做额外操作
写法如下:
public MainActivity extends FragmentActivity{ private void test(){ UserViewModel userModel = ViewModelProviders.of(this).get(UserViewModel.class); } }
用户数据实体(表)的创建:
package com.room.test.model;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Index;
/**
* 卡片
*/
@Entity(tableName = "user_table",//用户表
primaryKeys = {"userId" },//主键
indices = {@Index(value = "userId",unique = true)})//创建索引,可以不写,主要是避免编译警告
public class UserModel {
@NonNull
@ColumnInfo(name = "userId")
private String userId = "1";
@NonNull
@ColumnInfo(name = "userName",defaultValue = "")//默认值
private String userName = "";
@NonNull
@ColumnInfo(name = "sex",defaultValue = "('Created at' || CURRENT_TIMESTAMP)")
private String sex = "0";//0 男 1 女
@NonNull
@ColumnInfo(name = "headPic")
private String headPic = "";//头像
@NonNull
@ColumnInfo(name = "friendStatus")
private String friendStatus = "";//好友状态,是不是好友
@NonNull
public String getUserId() {
return userId;
}
public void setUserId(@NonNull String userId) {
this.userId = userId;
}
@NonNull
public String getUserName() {
return userName;
}
public void setUserName(@NonNull String userName) {
this.userName = userName;
}
@NonNull
public String getSex() {
return sex;
}
public void setSex(@NonNull String sex) {
this.sex = sex;
}
@NonNull
public String getHeadPic() {
return headPic;
}
public void setHeadPic(@NonNull String headPic) {
this.headPic = headPic;
}
@NonNull
public String getFriendStatus() {
return friendStatus;
}
public void setFriendStatus(@NonNull String friendStatus) {
this.friendStatus = friendStatus;
}
@Override
public String toString() {
return "UserModel{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", headPic='" + headPic + '\'' +
", friendStatus='" + friendStatus + '\'' +
'}';
}
}
创建数据表的操作类(Dao类)
package com.room.test.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
import com.room.test.model.UserModel;
import java.util.List;
@Dao
public interface UserDao {//该类可以是接口也可以是抽象类,抽象类的话可以做些额外操作,比如用事务,对于某系数据进行复杂操作,例如,首页未读消息的提示,先判断本地有没有,有的话就把未读消息数取出并进行更新,
@Insert(onConflict = OnConflictStrategy.IGNORE)//冲突策略,这个是忽略,如果想替换的话使用OnConflictStrategy.REPLACE
void insert(UserModel word);
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(List<UserModel> word);
@Query("SELECT * from user_table ORDER BY userId ASC")
LiveData<List<UserModel>> getAlphabetizedUser();//通过用liveData对数据进行监听,当数据库的数据进行改变后,该方法会被触发,自动进行回调
@Update
void update(UserModel word);//这个会根据唯一主键进行修改
@Query("UPDATE user_table SET userName = :name WHERE userId = :id")
void updateForUserId(String id,String name);
@Query("DELETE FROM user_table")
void deleteAll();
@Query("SELECT * from user_table WHERE userId = :userId")
LiveData<UserModel> getUserByUserId(String userId);
}
数据库的创建
- 注意该类中的方法必须最终是在ViewModel中执行,否则无法通过编译,哪怕是写个静态变量也无法在其他地方使用
package com.room.test.db;
import android.content.Context;
import android.text.TextUtils;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.room.test.dao.TeamUserJoinDao;
import com.room.test.dao.UserDao;
import com.room.test.dao.TeamDao;
import com.room.test.model.UserModel;
import com.room.test.model.TeamModel;
import com.room.test.model.TeamUserJoinModel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Database(entities = {
UserModel.class//定义的数据实体需要在这里进行定义
},
version = 1,//数据库版本
exportSchema = false)
public abstract class UserDatabase extends RoomDatabase {
public abstract UserDao cardDao();//通过抽象方法将数据实体操作类进行返回
private static volatile UserDatabase INSTANCE;//通过单一实例进行数据库的创建
private static final int NUMBER_OF_THREADS = 4;
public static final ExecutorService databaseWriteExecutor =
Executors.newFixedThreadPool(NUMBER_OF_THREADS);
public static UserDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (UserDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
UserDatabase.class, "user_database")//数据库名
.build();
}
}
}
return INSTANCE;
}
}
仓库中心(Repository)
package com.room.test.repository;
import android.app.Application;
import androidx.lifecycle.LiveData;
import com.room.test.dao.UserDao;
import com.room.test.db.UserDatabase;
import com.room.test.model.UserModel;
import java.util.List;
public class UserRepository {
private UserDao uUserDao;
private LiveData<List<UserModel>> mAllUser;
public UserRepository(Application application) {
UserDatabase db = UserDatabase.getDatabase(application);
uUserDao = db.cardDao();
mAllUser = uUserDao.getAlphabetizedUser();
}
// Room executes all queries on a separate thread.
// Observed LiveData will notify the observer when the data has changed.
public LiveData<List<UserModel>> getAllUser() {
return mAllUser;
}
public void insert(final UserModel user) {
UserDatabase.databaseWriteExecutor.execute(new Runnable() {
@Override
public void run() {
uUserDao.insert(user);
}
});
}
public void insert(final List<UserModel> user) {
UserDatabase.databaseWriteExecutor.execute(new Runnable() {
@Override
public void run() {
uUserDao.insert(user);
}
});
}
}
数据处理中心(ViewModel)
package com.room.test.viewmodel;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import com.room.test.model.UserModel;
import com.room.test.repository.UserRepository;
import java.util.List;
public class UserViewModel extends AndroidViewModel{
private UserRepository mRepository;
private LiveData<List<UserModel>> mAllUser;
public UserViewModel(@NonNull Application application) {
super(application);
mRepository = new UserRepository(application);
mAllUser = mRepository.getAllUser();
}
public LiveData<List<UserModel>> getAllUser() { return mAllUser; }
public void insert(UserModel user) { mRepository.insert(user); }
public void insert(List<UserModel> user) { mRepository.insert(user); }
}
操作测试
package com.room.test;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.room.test.model.TeamUserJoinModel;
import com.room.test.model.UserModel;
import com.room.test.model.TeamModel;
import com.room.test.viewmodel.UserViewModel;
import com.room.test.viewmodel.TeamCardViewModel;
import com.room.test.viewmodel.TeamViewModel;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private View addCard;
private View queryCard;
private UserViewModel userViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initViewModel();
}
private void initView(){
addCard = findViewById(R.id.add_card);
queryCard = findViewById(R.id.query_card);
addCard.setOnClickListener(this);
queryCard.setOnClickListener(this);
}
private void initViewModel(){
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.add_card:
userViewModel.insert(createCard());
break;
case R.id.query_card:
userViewModel.getAllUser().observe(this, new Observer<List<UserModel>>() {
@Override
public void onChanged(List<UserModel> userModels) {
for (UserModel user : userModels){
Log.e("YM","用户数据:"+user.toString());
}
}
});
break;
}
}
private List<UserModel> createCard(){
List<UserModel> users = new ArrayList<>();
UserModel user1 = new UserModel();
user1.setUserId("01");
UserModel user2 = new UserModel();
user2.setUserId("02");
UserModel user3 = new UserModel();
user3.setUserId("03");
UserModel user4 = new UserModel();
user4.setUserId("04");
users.add(user1);
users.add(user2);
users.add(user3);
users.add(user4);
return users;
}
}
至此,一个基础简单的示例已经编写完成。
参考链接:
在Google的官方文档部分API描述中,除了对api的解释,还包含了示例代码,而关于ROOM的这一章节,都有相关的示例代码演示。所以下文的引用仅仅只列出Database的引用地址,其他略去
ROOM架构简要描述 https://developer.android.com/topic/libraries/architecture/room
使用ROOM将数据保存到本地:https://developer.android.com/training/data-storage/room
Database API: https://developer.android.com/reference/androidx/room/Database
本文所使用的演示代码地址:https://github.com/mayangming/RoomTest.git