本是青灯不归客,却因浊酒恋红尘
一,基本使用
关于Room数据库的基本使用,请参考文章Android--Jetpack--数据库Room详解一-CSDN博客
二,Room与ViewModle,LiveData的结合使用
LiveData与ViewModle的使用,请参考文章Android--Jetpack--LiveData-CSDN博客
我们通过结合Room与LiveData和ViewModle的使用,可以使当我们的数据库发生变化的时候,自动的去更新UI。
下面来看一个简单的使用案例:
1,还是 Android--Jetpack--数据库Room详解一-CSDN博客
中创建的数据库,表还是YuanZhen这张表, 我们把YuanZhenDao这个Dao类添加一个新的方法,使得可以查询到LiveData包装的集合:
@Dao
public interface YuanZhenDao {
@Insert
void insert(YuanZhen... yuanzhens);
@Delete
void delete(YuanZhen yuanZhen);
@Update
void update(YuanZhen yuanZhen);
@Query("select * from YuanZhen")
List<YuanZhen> getAll();
@Query("select * from YuanZhen where name like :name")
YuanZhen getByName(String name);
@Query("select * from YuanZhen where age in(:ages)")
List<YuanZhen> getByAges(int[] ages);
@Query("select name,address from YuanZhen ")
public List<YuanZhenNew> getNew();
@Query("select * from YuanZhen")
LiveData<List<YuanZhen>> getAllLiveDataYZ();
}
2,将数据库MyDatabase修改为单例模式:
@Database(entities = {YuanZhen.class},version = 1)
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase instance;
public static synchronized MyDatabase getInstance(Context context){
if(instance==null){
instance= Room.databaseBuilder(context.getApplicationContext(),MyDatabase.class
,"YuanZhenDb")
.build();
}
return instance;
}
public abstract YuanZhenDao yuanZhenDao();
}
3,创建一个包装类,包装LiveData给ViewModel使用:
public class YuanZhenDecorate {
private LiveData<List<YuanZhen>> liveDataAllYZ;
private YuanZhenDao yuanZhenDao;
public YuanZhenDecorate(Context context) {
yuanZhenDao =MyDatabase.getInstance(context).yuanZhenDao();
if(liveDataAllYZ==null){
liveDataAllYZ=yuanZhenDao.getAllLiveDataYZ();
}
}
void insert(YuanZhen... yuanZhens){
yuanZhenDao.insert(yuanZhens);
}
void delete(YuanZhen yuanZhen){
yuanZhenDao.delete(yuanZhen);
}
void update(YuanZhen yuanZhen){
yuanZhenDao.update(yuanZhen);
}
List<YuanZhen> getAll(){
return yuanZhenDao.getAll();
}
LiveData<List<YuanZhen>> getAllLiveDataYZ(){
return yuanZhenDao.getAllLiveDataYZ();
}
}
4,创建一个viewmodle:
public class YZViewModdel extends AndroidViewModel {
private YuanZhenDecorate yuanZhenDecorate;
public YZViewModdel(@NonNull Application application) {
super(application);
yuanZhenDecorate =new YuanZhenDecorate(application);
}
void insert(YuanZhen... yuanZhens){
yuanZhenDecorate.insert(yuanZhens);
}
void delete(YuanZhen yuanZhen){
yuanZhenDecorate.delete(yuanZhen);
}
void update(YuanZhen yuanZhen){
yuanZhenDecorate.update(yuanZhen);
}
List<YuanZhen> getAll(){
return yuanZhenDecorate.getAll();
}
LiveData<List<YuanZhen>> getAllLiveDataYZ(){
return yuanZhenDecorate.getAllLiveDataYZ();
}
}
5,创建一个recyclerview的adapter:
public class MyAdapter extends RecyclerView.Adapter {
private LayoutInflater mLayoutInflater;
private List<YuanZhen> mList;
public MyAdapter(Context context,List<YuanZhen> mList) {
mLayoutInflater =LayoutInflater.from(context);
this.mList =mList;
}
public void setData(List<YuanZhen> mList) {
this.mList = mList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(mLayoutInflater.inflate(R.layout.item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
((ViewHolder)holder).mTxt.setText(mList.get(position).getName());
}
@Override
public int getItemCount() {
if(mList!=null){
return mList.size();
}
return 0;
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView mTxt;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTxt = (TextView) itemView.findViewById(R.id.txt);
}
}
}
6,activity的xml布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_room"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
7,item的xml布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txt"
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="16sp"/>
</RelativeLayout>
8,使用:
public class MainActivity extends AppCompatActivity {
StudentViewModel studentViewModel;
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = findViewById(R.id.listView);
studentViewModel = ViewModelProviders.of(this).get(StudentViewModel.class);
studentViewModel.getAllLiveDataStudent().observe(this, new Observer<List<Student>>() {
@Override
public void onChanged(List<Student> students) {
listView.setAdapter(new GoodsAdapter(MainActivity.this, students));
}
});
for (int i = 0; i < 50; i++) {
studentViewModel.insert(new Student("jett", "123", 1));
}
new Thread() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
studentViewModel.update(new Student(6, "jett" + i, "123", 1));
}
}
}.start();
}
}
9,运行:
三,数据库的升级
1,强制升级,执行之后数据库的结构会发生变化,但是数据库的数据会丢失。
这种情况比较适合toB开发,数据库版本高降到低的情况,紧急发一版新的程序给现场升级。
使用 :fallbackToDestructiveMigration()
@Database(entities = {YuanZhen.class},version = 2)
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase instance;
public static synchronized MyDatabase getInstance(Context context){
if(instance==null){
instance= Room.databaseBuilder(context.getApplicationContext(),MyDatabase.class
,"YuanZhenDb")
//强制升级
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
public abstract YuanZhenDao yuanZhenDao();
}
2,一般的升级方式
假如我们要增加一个字段price:
@Entity
public class YuanZhen {
@PrimaryKey(autoGenerate = true)
private int id;
@ColumnInfo(name ="name")
private String name;
@ColumnInfo(name ="age")
private int age;
@ColumnInfo(name ="address")
private String address;
@ColumnInfo(name = "price")
private int price;
@Ignore
private String sex;
public YuanZhen(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return "YuanZhen{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
在MyDatabase中增加升级功能:
@Database(entities = {YuanZhen.class},version = 2,exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase instance;
public static synchronized MyDatabase getInstance(Context context){
if(instance==null){
instance= Room.databaseBuilder(context.getApplicationContext(),MyDatabase.class
,"YuanZhenDb")
//强制升级
// .fallbackToDestructiveMigration()
.addMigrations(MIGRATION_1_2)
.build();
}
return instance;
}
public abstract YuanZhenDao yuanZhenDao();
static final Migration MIGRATION_1_2=new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
//在这里用sql脚本完成数据变化
database.execSQL("alter table yuanzhen add column price integer not null default 1");
}
};
}
这里和greendao最大的不同就是,这里需要自己去写升级脚本,虽然增加了工作量,但是也更加灵活了。