Android JetPack之ROOM(一)

前言:

​ 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章