Jetpack学习笔记(一):使用Room和AsyncTask来处理数据库

1、使用Room创建数据库

Jetpack下使用Room创建数据库,相较于之前使用DBhelper创建,更像是平常创建一个对象一样简单,使用标记让大部分代码可以有IDE自动完成


2、创建数据库存储对象

相当于DBhelper中创建一个表,将之前的数据库语句具象成一个对象,就如同创建普通对象一样,只需要在对象前加一个标记 @Entity (实体),该对象会自动被识别,对象中的每个属性相当于数据库中的一个个字段,使用标记就可以声明主键等等;

1、创建一个实体对象
@Entity
public class People {
    //主键自增加
    @PrimaryKey(autoGenerate =true)
    private int _id;
    @ColumnInfo(name="name")
    private String name="";
    @ColumnInfo(name = "college")
    private String college="未设置";
    @ColumnInfo(name = "age")
    private int age=19;
    }

其中@PrimaryKey(autoGenerate =true)即声明该字段为主键,并且自增,@ColumnInfo(name = "xxx")是给字段在数据库中的命名,如果不加默认会以变量名作为字段明

2、书写对象内的一些方法

这里就和构造普通的对象一样,可以在实体对象中定义不同的方法调用,例如构造方法GET/SETtoString……
示例:

  public People(String name) {
        this.name = name;
    }

    public People(String name, String college) {
        this.name = name;
        this.college = college;
    }

    public int get_id() {
        return _id;
    }

    public void set_id(int _id) {
        this._id = _id;
    }

    public String getName() {
        return name;
    }
    ……

3、创建操作接口

***相当于进行Provider操作*有了对象实体,还需要定义操作接口,即Romm中的@Dao(database access object–数据库访问对象),用于对数据库进行操作,同样利用 标记 简化了数据库操作

1、增

使用@Insert标记,并且传入之前定义的对象实体即可:

@Insert
    void InsertPeo(People... people);

注意:其中People...表示可以传入一个或多个相同类型的参数

2、删

同样使用@Delete标记加上实体对象即可,相当于简化了之前where语句,直接将一个对象作为参数,只要符合该对象就可以对其进行删除操作:

  @Delete
    int deletePeo(People... people);
3、改

利用@Update语句传入对象即可进行操作:
默认按照主键修改

@Update
    int updatePeo(People... people);
4、查和其他操作

和上述增、删、改的操作不同,Query可以除了查询做更多的事情,它更像是一个条件操作,同样利用@Query()标记进行书写,与此不同的()类需要写入SQL语句,从而执行相应的操作:

 @Query("SELECT * FROM People")
    List<Word> getPeoAll();

    @Query("DELETE FROM People")
    void delAllPeo();

如上,分别是查询全部删除全部的操作,举一反三可以定义更多的操作;

创建抽象类进行操作

这一步相当于DBhelper中的创建数据库,创建一个抽象方法并继承RoomDatabase利用@Database()标记进行数据库的创建操作,其中包含几个参数,一个是entities——即之前创建的实体,这一步相当于告知在本数据库放入那些表,version即字面意思,数据库的版本,用于后续升级使用:

@Database(entities = {People.class},version = 1)
public abstract class PeopleDatabase extends RoomDatabase {
    public abstract PeopleDao getPeoDao();
}

以上所有使用标记部分,均相当于抽象类,IDE会生成相应的mpl代码,可以使用IDE中的方法实现功能查看相应的实现代码;


在程序中访问数据库

1、创建数据库访问对象

利用Room方法生成一个之前定义的抽象类,以才来构造数据库的访问:

 peopleDatabase=Room.databaseBuilder(this,PeopleDatabase.class,"People")
 .build();

其中构建的三个参数分别是:

  • 上下文对象
  • 数据库抽象类
  • 数据库名称

需要说明的是该方法因为是耗时操作,如果直接在UI线程中运行会报错,此时需要使用allowMainThreadQueries()方法构造,强制允许在UI线程中运行

2、创建数据库操作方法

直接从刚刚获得的数据库对象中调用之前创建的getDao方法获取数据库操作接口:

peopleDao=peopleDatabase.getPeoDao();

3、增删改查

分别调用之前在Dao中定义的方法并传入相应参数即可实现增删改查:

//增加
 peopleDao.InsertPeo(new People("冷朴承","数学与计算机学院"));
 peopleDao.InsertPeo(new People("小云快飞","数计学院")
 ,new People("玲儿"));
 People people=new People("林儿");
 people.setCollege("药学院");
 people.setAge(21);
 peopleDao.InsertPeo(people);
 //删除
People people=new People();
people.set_id(4);
peopleDao.deletePeo(people);
//修改
People people=new People("承儿","数学与计算机学院");
people.set_id(4);
peopleDao.updatePeo(people);
//查询
List<People> peopleList=peopleDao.getPeoAll(); 
String str="";
for(People people:peopleList){
str+=people.get_id()+":"+people.getName()+"--"+people.getCollege()
+"_age:"+people.getAge()+"\n";
        }
textView.setText(str);

可以看到之前的People...在这里可以传入多个参数或者一个参数,或者是数组链表等;


使用AsyncTask

AsyncTask是一个在UI下的异步线程,同时可以更新界面上的显示,用法是定义一个继承于AsyncTask的方法:

static class InsertAsyncTask extends AsyncTask<People,Void ,Void>{}

其中三个参数分别是,开始时的对象,进行中的对象,结束时候的对象,其中主要应用三个方法

1、线程开始前

复写onPreExecute方法可以在线程开始前执行,例如用它打开一个滚轮或者进度条,告知界面这是耗时操作:

//开始前
@Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
2、线程初始化

复写doInBackground方法,即表示线程启动进行什么操作,如下案例就是进行插入操作;

//做什么事情
 @Override
protected Void doInBackground(People... peoples) {
      peoDao.insertPeo(peoples);
      return null;
    }

该方法是AsyncTask必须复写的方法,表示的任务是该线程的主任务

3、线程正在进行时

复写onProgressUpdate即线程正在运行时候的回调,例如在这里动态滚动进度条等等;

    //当进度发生更新时候的操作
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
4、线程工作完成时

复写onPostExecute方法即可以在线程完成即将结束时操作

//线程完成时操作,一般将结果带回给主线程
 @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
        }

调用AsyncTask

new UpdateAsyncTask(peopleDao).execute(people);

优化数据库

1、静态DataBase

使用synchronized其只有唯一一个对象节约资源占用

@Database(entities = {People.class},version = 1)
public abstract class PeopleDatabase extends RoomDatabase {
    private static  PeopleDatabase INSTANCE;
    static synchronized PeopleDatabase getDatabase(Context context){
        if(INSTANCE ==null){
            INSTANCE= Room.databaseBuilder(context.getApplicationContext(),PeopleDatabase.class,"peo_data")
            .allowMainThreadQueries()
                     .build();
        }
        return INSTANCE;
    };
    public abstract PeopleDao getPeoDao();
}
2、动态LiveData

将所有和Query相关的返回为LiveData,既可对数据进行观察,方便后续的其他操作

    @Query("SELECT * FROM People")
    LiveData<List<People>> getPeoAll();

添加观察者

 LiveData<List<People>> allPeos;
 allPeos=peopleDao.getPeoAll();
  allPeos.observe(this, new Observer<List<People>>() {
            @Override
            public void onChanged(List<People> people) {
                StringBuilder str= new StringBuilder();
                for(People peo:people){
                    str.append(peo.get_id()).append(":").append(peo.getName()).append("_").append(peo.getCollege()).append("_").append(peo.getAge()).append("\n");
                }
                textView.setText(str.toString());
            }
        });

就可以在数据发生改变时,动态的修改UI界面

3、ViewModel解耦Activity

需要先在dependencies中添加依赖
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
否则生成ViewMode需要传入另一个参数

1、创建ViewMode

为了后续维护和扩展便捷,将数据操作于界面分离,故创建ViewModel对象来管理界面上的数据

继承AndroidViewModel可以让系统管理生命周期

public class PeopleViewModel extends AndroidViewModel {
LiveData<List<People>> getAllPeos() {
        return repository.getAllPeos();
    }
……
}

Activity中调用ViewModelProvider方法来构造

PeopleViewModel peopleViewModel= new ViewModelProvider(this).get(PeopleViewModel.class);
2、创建Repository工具类进一步解耦

刚刚创建的ViewModel中分离了界面与数据,但是其中还是会掺和着与启动线程、获取数据相关的操作,为了进一步的扩展,将数据库操作完全与界面解耦,定义一个Repository类,封装所有的数据库操作

class PeopleRepository {
    private LiveData<List<People>> allPeos;
    private PeopleDao peopleDao;
    PeopleRepository(Context context){
        PeopleDatabase peopleDatabase=PeopleDatabase.getDatabase(context.getApplicationContext());
         peopleDao=peopleDatabase.getPeoDao();
        allPeos=peopleDao.getPeoAll();
    }

    LiveData<List<People>> getAllPeos() {
        return allPeos;
    }

    void insertPeo(People... people){
        new InsertAsyncTask(peopleDao).execute(people);
    }
    void delPeo(People... people){
        new DeleteAsyncTask(peopleDao).execute(people);
    }
    void updatePeo(People... people){
        new UpdateAsyncTask(peopleDao).execute(people);
    }
    void delAll(){
        new DelAllAsyncTask(peopleDao).execute();
    }
    //一个异步线程  三个参数  对象,进度,结果
   public static class InsertAsyncTask extends AsyncTask<People,Void ,Void>{
        private PeopleDao peoDao;

        InsertAsyncTask(PeopleDao peoDao) {
            this.peoDao=peoDao;
        }

        @Override
        protected Void doInBackground(People... peoples) {
            peoDao.insertPeo(peoples);
            return null;
        }
    }



    static class UpdateAsyncTask extends AsyncTask<People,Void ,Void>{
        private PeopleDao peoDao;

        UpdateAsyncTask(PeopleDao peoDao) {
            this.peoDao=peoDao;
        }

        @Override
        protected Void doInBackground(People... peoples) {
            peoDao.updatePeo(peoples);
            return null;
        }
    }

    static class DeleteAsyncTask extends AsyncTask<People,Void ,Void>{
        private PeopleDao peoDao;

        DeleteAsyncTask(PeopleDao peoDao) {
            this.peoDao=peoDao;
        }

        @Override
        protected Void doInBackground(People... peoples) {
            peoDao.deletePeo(peoples);
            return null;
        }
    }

    //void即缺省
    static class DelAllAsyncTask extends AsyncTask<Void,Void ,Void> {
        private PeopleDao peoDao;

        DelAllAsyncTask(PeopleDao peoDao) {
            this.peoDao=peoDao;
        }

        @Override
        protected Void doInBackground(Void... voids) {
            peoDao.delAllPeo();
            return null;
        }
    }

}
3、ViewModel回调Repository接口
public class PeopleViewModel extends AndroidViewModel {
    private PeopleRepository repository;
    public PeopleViewModel(@NonNull Application application) {
        super(application);
        repository=new PeopleRepository(application);
    }

    LiveData<List<People>> getAllPeos() {
        return repository.getAllPeos();
    }

    void insertPeo(People... people){
        repository.insertPeo(people);
    }
    void delPeo(People... people){
        repository.delPeo(people);
    }
    void updatePeo(People... people){
        repository.updatePeo(people);
    }
    void delAll(){
       repository.delAll();
    }



}
4、在Activity中使用案例
public class MainActivity extends AppCompatActivity {
    TextView textView;
    Button button5, button6, button7, button8;

    //创建ViewModel实例
    PeopleViewModel peopleViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        peopleViewModel = new ViewModelProvider(this).get(PeopleViewModel.class);
        textView = findViewById(R.id.textView);
        peopleViewModel.getAllPeos().observe(this, new Observer<List<People>>() {
            @Override
            public void onChanged(List<People> people) {
                StringBuilder str = new StringBuilder();
                for (People peo : people) {
                    str.append(peo.get_id()).append(":").append(peo.getName()).append("_").append(peo.getCollege()).append("_").append(peo.getAge()).append("\n");
                }
                textView.setText(str.toString());
            }
        });
        button5 = findViewById(R.id.button5);
        button5.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                People people = new People("林儿");
                people.setCollege("药学院");
                people.setAge(21);
                peopleViewModel.insertPeo(new People("冷朴承", "数学与计算机学院")
                        , new People("小云快飞", "数计学院")
                        , new People("玲儿"), people);
            }

        });
        button6 = findViewById(R.id.button6);
        button6.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                People people = new People();
                people.set_id(4);
                peopleViewModel.delPeo(people);

            }
        });

        button7 = findViewById(R.id.button7);
        button7.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                People people = new People("承儿", "数学与计算机学院");
                people.set_id(4);
                peopleViewModel.updatePeo(people);

            }
        });
        button8 = findViewById(R.id.button8);
        button8.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                peopleViewModel.delAll();
            }
        });


    }


}

至此一个使用Room的数据库定义到访问完成,虽然相比于原生的getContentResolver()可能看起来类变多了,但实际在书写上和归类上都简化了,而且将数据和界面解耦,让后续的维护和扩展更加便捷,特别是将数据表具象为一个实体对象,可以像创建普通的对象一样使用,极大的简化了操作

发布了7 篇原创文章 · 获赞 7 · 访问量 1765

猜你喜欢

转载自blog.csdn.net/XiaoYunKuaiFei/article/details/105639153