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

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