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

Android MVVM框架搭建MMKV + Room + RxJava2

Android 数据存储-Room

Android 数据存储-Room

Android 数据存储-Room

Android 数据存储-Room