前言:
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