Android Room牛刀小试
Posted 碎格子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Room牛刀小试相关的知识,希望对你有一定的参考价值。
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-beta1
Error: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
@Dao
public interface BookDao
//这里使用Maybe
@Query("SELECT * FROM book")
Maybe<List<Book>> getAllBooks();
@Query("SELECT * FROM book where bookid = :id")
Maybe<Book> 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<Book> 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<List<Book>>()
@Override
public void accept(@NonNull List<Book> 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<Book>()
@Override
public void accept(@NonNull Book book) throws Exception
ArrayList<Book> 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<Book> 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结尾的类里面是怎么实现的。
以上是关于Android Room牛刀小试的主要内容,如果未能解决你的问题,请参考以下文章
Android MVVM框架搭建MMKV + Room + RxJava2