Android(安卓)Room牛刀小试
16lz
2021-01-26
Room在SQLite之上提供了一个抽象层来访问数据库,可以在充分利用SQLite强大功能的同时对数据库进行流畅的访问。
优点
- 减少了写大量代码来在SQL查询和Java数据对象之间进行转换。
- 数据层改变自动更新SQL查询。减少了查询过程的耗时。
使用
添加依赖
compile "android.arch.persistence.room:runtime:1.0.0-beta1"annotationProcessor "android.arch.persistence.room:compiler:1.0.0-beta1"
可能发生的错误
Error:Failed to resolve: android.arch.persistence.room:runtime:1.0.0-beta1Error:Failed to resolve: annotationProcessor
解决办法:
往工程级别下的gradle文件里添加google的maven仓库
allprojects { repositories { jcenter() maven { url 'https://maven.google.com' } }}
Room三要素:
- Dao:用来处理数据库操作,如增删改查,编译的时候会生成_impl结尾的实现类,实现在DAO中定义的增删改查方法
- Entity:实体类,一个实体类对应一张表
- Database:作为底层连接数据库的主要接入点,它是一个抽象的类,并继承RoomDatabase,编译的时候会自动生成一个_impl结尾的实现类,实现数据库以及表的创建及打开
代码:
Tips:这里使用了RxJava2.0里的Completable以及Maybe用来处理数据库操作,以及ui更新。
为什么用Maybe不用Single?Maybe是发送0个或1个数据,而single是发送一个数据并且结果要么成功要么错误抛异常。
创建一个DAO接口,这个接口主要是提供数据库增删改查方法,编译的时候会生成一个BookDao_Impl的实现类:
BookDao.java
@Daopublic interface BookDao { //这里使用Maybe @Query("SELECT * FROM book") Maybe> getAllBooks(); @Query("SELECT * FROM book where bookid = :id") Maybe getBookById(int id); @Insert void insertAll(Book... books); @Delete void delete(Book book); @Update void updateBooks(Book... books);}
Entity: 一个实体类对应一张表
Book.java
@Entity(tableName = "book")public class Book { @PrimaryKey(autoGenerate = true) private int bookid; @ColumnInfo(name = "book_name") private String bookName; @ColumnInfo(name = "author") private String author; public void setAuthor(String author) { this.author = author; } public String getAuthor() { return author; } public void setBookid(int bookid) { this.bookid = bookid; } public int getBookid() { return bookid; } public void setBookName(String bookName) { this.bookName = bookName; } public String getBookName() { return bookName; }}
Database:抽象类,编译的时候会生成一个BookDatabase_Impl实现类,实现数据库和表的创建打开,并且实现bookDao()方法
BookDatabase.java
@Database(entities = {Book.class}, version = 1)public abstract class BookDatabase extends RoomDatabase { public abstract BookDao bookDao();}
DatabaseCallback.java 用于更新ui和提示操作结果
public interface DatabaseCallback { void onLoadBooks(List books); void onAdded(); void onDeleted(); void onUpdated(); void onError(String err);}
创建一个Manager方便我们对数据库进行管理操作:
注意:数据库的操作要在子线程中进行,不要在主线程进行操作
LocalCacheManager.java
public class LocalCacheManager { private static LocalCacheManager _instance; private BookDatabase db; private static final String DB_NAME = "book-database"; public static LocalCacheManager getInstance(Context context) { if (_instance == null) { _instance = new LocalCacheManager(context); } return _instance; } public LocalCacheManager(Context context) { db = Room.databaseBuilder(context, BookDatabase.class, DB_NAME).build(); } public void getBooks(final DatabaseCallback databaseCallback) { db.bookDao() .getAllBooks() //在io线程进行数据库操作 .subscribeOn(Schedulers.io()) //在主线程进行数据反馈 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer>() { @Override public void accept(@NonNull List books) throws Exception { databaseCallback.onLoadBooks(books); } }); } public void addBook(final DatabaseCallback databaseCallback, final Book... books) { //这里使用Completable是因为数据库处理完后不发射数据,只处理onComplete 和 onError 事件 Completable .fromAction(new Action() { @Override public void run() throws Exception { db.bookDao().insertAll(books); } }) //在主线程进行反馈 .observeOn(AndroidSchedulers.mainThread()) //在io线程进行数据库操作 .subscribeOn(Schedulers.io()) .subscribe(new CompletableObserver() { @Override public void onSubscribe(Disposable d) { } @Override public void onComplete() { databaseCallback.onAdded(); } @Override public void onError(Throwable e) { databaseCallback.onError(e.getMessage()); } }); } public void delete(final DatabaseCallback databaseCallback, final int id) { Completable .fromAction(new Action() { @Override public void run() throws Exception { Book book = new Book(); book.setBookid(id); db.bookDao().delete(book); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new CompletableObserver() { @Override public void onSubscribe(Disposable d) { } @Override public void onComplete() { databaseCallback.onDeleted(); } @Override public void onError(Throwable e) { databaseCallback.onError(e.getMessage()); } }); } public void getBookById(final DatabaseCallback callback, int id) { db.bookDao().getBookById(id).observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(new Consumer() { @Override public void accept(@NonNull Book book) throws Exception { ArrayList list = new ArrayList<>(); list.add(book); callback.onLoadBooks(list); } }); } public void updateBook(final DatabaseCallback callback, final Book... book) { Completable.fromAction(new Action() { @Override public void run() throws Exception { db.bookDao().updateBooks(book); } }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new CompletableObserver() { @Override public void onSubscribe(Disposable d) { } @Override public void onComplete() { callback.onUpdated(); } @Override public void onError(Throwable e) { callback.onError(e.getMessage()); } }); }}
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, DatabaseCallback { TextView panel; Button btnAdd, btnDelete, btnSelect,btnUpdate; EditText etName, etId, etAuthor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnAdd = findViewById(R.id.add); btnDelete = findViewById(R.id.delete); btnSelect = findViewById(R.id.select); etName = findViewById(R.id.name); etId = findViewById(R.id.id); etAuthor = findViewById(R.id.author); panel = findViewById(R.id.panel); btnUpdate = findViewById(R.id.update); btnAdd.setOnClickListener(this); btnDelete.setOnClickListener(this); btnSelect.setOnClickListener(this); btnUpdate.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.add: if (etName.getText().toString().trim().length() > 0 && etAuthor.getText().toString().trim().length() > 0 && etId.getText().toString().trim().length() > 0) { final Book book = new Book(); book.setAuthor(etAuthor.getText().toString().trim()); book.setBookName(etName.getText().toString().trim()); LocalCacheManager.getInstance(getApplicationContext()).addBook(MainActivity.this, book); } else { Toast.makeText(this, "Please input", Toast.LENGTH_SHORT).show(); } break; case R.id.delete: if (etId.length() > 0) { LocalCacheManager.getInstance(getApplicationContext()).delete(MainActivity.this, Integer.parseInt(etId.getText().toString().trim())); } break; case R.id.select: if (etId.length() > 0) { LocalCacheManager.getInstance(getApplicationContext()).getBookById(MainActivity.this, Integer.parseInt(etId.getText().toString().trim())); } else { LocalCacheManager.getInstance(getApplicationContext()).getBooks(MainActivity.this); } break; case R.id.update: if (etId.length() > 0) { final Book book = new Book(); book.setBookid(Integer.parseInt(etId.getText().toString().trim())); book.setAuthor(etAuthor.getText().toString().trim()); book.setBookName(etName.getText().toString().trim()); LocalCacheManager.getInstance(getApplicationContext()).updateBook(MainActivity.this, book); } break; } } @Override public void onLoadBooks(List books) { panel.setText(""); for (Book book : books) { panel.append("\nID:" + book.getBookid() + "\nName:" + book.getBookName() + "\nAuthor:" + book.getAuthor()); } } @Override public void onAdded() { Toast.makeText(this, "Add Successfully", Toast.LENGTH_SHORT).show(); } @Override public void onDeleted() { Toast.makeText(this, "Deleted Successfully", Toast.LENGTH_SHORT).show(); } @Override public void onUpdated() { Toast.makeText(this, "Updated Successfully", Toast.LENGTH_SHORT).show(); } @Override public void onError(String err) { Toast.makeText(this, err, Toast.LENGTH_SHORT).show(); }}
运行发现警告错误:
Error: Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
解决办法:
在app module下的gradle文件里添加下面代码:
android { ... defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] } } } ...}
最后
相比Sqlite,Room上手非常简单,因为有关数据库以及表的创建,还有增删改查的实现,都在编译的时候自动帮你写好了,我们只需要关心在哪个线程调用哪个方法进行处理,不需要关心具体实现。但是还是建议新手有时间可以看看_Impl结尾的类里面是怎么实现的。
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- GreenDao 3.3.0 增删改查的使用(三)
- Android(安卓)registerContentObserver 接口监视数据库变化
- 安卓数据库连接解决办法 ,避免 sqlite3 database is locked
- 学习ContentProvider---之一:查询数据库
- RxJava(九)zip 操作符在 Android(安卓)中的实际使用场景
- Android(安卓)Bluetooth 蓝牙基本操作
- 梳理Android的IPC进程间通信(最新AndroidStudio的AIDL操作)
- 10、Android数据存储