【问题标题】:Implementing the Room Database (Android)实现房间数据库 (Android)
【发布时间】:2018-04-12 14:54:48
【问题描述】:

我想知道如何将 Room Library 正确集成到 Android 应用程序中。我看到的一些文章使用单例方法,使用 Respository 进行数据库调用,而其他文章使用某种形式的 Dependecy Injection (Dagger 2)。我想知道这个库的正确集成?

谢谢

【问题讨论】:

    标签: android database sqlite android-room android-livedata


    【解决方案1】:

    房间基础知识

    Room 库充当底层 SQLite 数据库的抽象层。因此,使用了 Room 注释:

    1. 到数据库和实体,其中实体是表示表结构的 POJO 类。
    2. 指定检索、更新和删除操作。
    3. 添加约束,例如外键。
    4. 支持 LiveData。

    Room 中有 3 个主要组件

    1. Entity:使用@Entity 注释注释的类映射到数据库中的表。每个实体都保存在自己的表中,类中的每个字段都代表列名。

    tableName 属性用于定义表的名称 每个实体类必须至少有一个主键字段,用@PrimaryKey 注释 实体类中的字段可以用@ColumnInfo(name = “name_of_column”)注解来给出具体的列名

    1. DAO:数据访问对象可以是一个接口,也可以是一个带有@Doa 注释的抽象类,包含定义要对数据执行的操作的所有方法。方法可以用注释

    @Query 从数据库中检索数据

    @Insert 将数据插入数据库

    @Delete 从数据库中删除数据

    @Update 更新数据库中的数据

    1. 数据库:数据库是表的容器。使用@Database 注解注解的抽象类用于创建具有给定名称和数据库版本的数据库。

    添加这些依赖项:

        dependencies {
        // Room dependencies
          compile 'android.arch.persistence.room:runtime:1.0.0'
          annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
        }
    

    创建实体

    在创建数据库之前,我们先创建一个Entity,命名为Note,之后,这个类的对象会被添加到数据库中。

        @Entity
    public class Note {
    
        @PrimaryKey(autoGenerate = true)
        private int note_id;
    
        @ColumnInfo(name = "note_content") // column name will be "note_content" instead of "content" in table
        private String content;
    
        private String title;
    
        private
    
        public Note(int note_id, String content, String title) {
            this.note_id = note_id;
            this.content = content;
            this.title = title;
        }
    
        public int getNote_id() {
            return note_id;
        }
    
        public void setNote_id(int note_id) {
            this.note_id = note_id;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Note)) return false;
    
            Note note = (Note) o;
    
            if (note_id != note.note_id) return false;
            return title != null ? title.equals(note.title) : note.title == null;
        }
    
    
    
        @Override
        public int hashCode() {
            int result = note_id;
            result = 31 * result + (title != null ? title.hashCode() : 0);
            return result;
        }
    
        @Override
        public String toString() {
            return "Note{" +
                    "note_id=" + note_id +
                    ", content='" + content + '\'' +
                    ", title='" + title + '\'' +
                    '}';
        }}
    

    创建 DAO

    DAO 定义了访问数据库的所有方法,并使用 @Dao 注释进行注释。 DAO 充当合约,对数据库中的数据执行 CRUD 操作。

        @Dao
    public interface NoteDao {
      @Query("SELECT * FROM user "+ Constants.TABLE_NAME_NOTE)
      List<Note> getAll();
    
    
      /*
      * Insert the object in database
      * @param note, object to be inserted
      */
      @Insert
      void insert(Note note);
    
      /*
      * update the object in database
      * @param note, object to be updated
      */
      @Update
      void update(Note repos);
    
      /*
      * delete the object from database
      * @param note, object to be deleted
      */
      @Delete
      void delete(Note note);
    
      /*
      * delete list of objects from database
      * @param note, array of objects to be deleted
      */
      @Delete
      void delete(Note... note);      // Note... is varargs, here note is an array
    
    }
    

    创建数据库

    现在,我们将表定义为实体和通过 NoteDao 定义的 CRUD 方法。数据库难题的最后一块是数据库本身。

    @Database(entities = { Note.class }, version = 1)
    public abstract class NoteDatabase extends RoomDatabase {
    
    public abstract NoteDao getNoteDao();
    
    private static NoteDatabase noteDB;
    
    public static NoteDatabase getInstance(Context context) {
    if (null == noteDB) {
    noteDB = buildDatabaseInstance(context);
    }
    return noteDB;
    }
    
    private static NoteDatabase buildDatabaseInstance(Context context) {
    return Room.databaseBuilder(context,
    NoteDatabase.class,
    Constants.DB_NAME)
    .allowMainThreadQueries().build();
    }
    
    public void cleanUp(){
    noteDB = null;
    }
    
    }
    

    实现数据库交互

    下面的 sn-p 将演示如何使用 Room 数据库进行插入、更新和删除功能。

    public class AddNoteActivity extends AppCompatActivity {
    
    private TextInputEditText et_title,et_content;
    private NoteDatabase noteDatabase;
    private Note note;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_note);
    et_title = findViewById(R.id.et_title);
    et_content = findViewById(R.id.et_content);
    noteDatabase = NoteDatabase.getInstance(AddNoteActivity.this);
    Button button = findViewById(R.id.but_save);
    
          button.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                // fetch data and create note object
                    note = new Note(et_content.getText().toString(),
                            et_title.getText().toString());
    
                    // create worker thread to insert data into database
                    new InsertTask(AddNoteActivity.this,note).execute();
              }
          });
    
    }
    
    private void setResult(Note note, int flag){
    setResult(flag,new Intent().putExtra("note",note));
    finish();
    }
    
    private static class InsertTask extends AsyncTask<Void,Void,Boolean> {
    
          private WeakReference<AddNoteActivity> activityReference;
          private Note note;
    
          // only retain a weak reference to the activity
          InsertTask(AddNoteActivity context, Note note) {
              activityReference = new WeakReference<>(context);
              this.note = note;
          }
    
          // doInBackground methods runs on a worker thread
          @Override
          protected Boolean doInBackground(Void... objs) {
              activityReference.get().noteDatabase.getNoteDao().insertNote(note);
              return true;
          }
    
            // onPostExecute runs on main thread
          @Override
          protected void onPostExecute(Boolean bool) {
              if (bool){
                  activityReference.get().setResult(note,1);
              }
          }
    
    }
    
    }
    

    检索并显示笔记列表

    public class NoteListActivity extends AppCompatActivity implements NotesAdapter.OnNoteItemClick{
    
    private TextView textViewMsg;
    private RecyclerView recyclerView;
    private NoteDatabase noteDatabase;
    private List<Note> notes;
    private NotesAdapter notesAdapter;
    private int pos;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initializeVies();
    displayList();
    }
    
    private void displayList(){
    // initialize database instance
    noteDatabase = NoteDatabase.getInstance(NoteListActivity.this);
    // fetch list of notes in background thread
    new RetrieveTask(this).execute();
    }
    
    private static class RetrieveTask extends AsyncTask<Void,Void,List<Note>>{
    
          private WeakReference<NoteListActivity> activityReference;
    
          // only retain a weak reference to the activity
          RetrieveTask(NoteListActivity context) {
              activityReference = new WeakReference<>(context);
          }
    
          @Override
          protected List<Note> doInBackground(Void... voids) {
              if (activityReference.get()!=null)
                  return activityReference.get().noteDatabase.getNoteDao().getNotes();
              else
                  return null;
          }
    
          @Override
          protected void onPostExecute(List<Note> notes) {
              if (notes!=null && notes.size()>0 ){
                  activityReference.get().notes = notes;
    
                  // hides empty text view
                  activityReference.get().textViewMsg.setVisibility(View.GONE);
    
                  // create and set the adapter on RecyclerView instance to display list
                  activityReference.get().notesAdapter = new NotesAdapter(notes,activityReference.get());
                  activityReference.get().recyclerView.setAdapter(activityReference.get().notesAdapter);
              }
          }
    
    }
    
    private void initializeVies(){
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    textViewMsg = (TextView) findViewById(R.id.tv\_\_empty);
    
          // Action button to add note
          FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
          fab.setOnClickListener(listener);
          recyclerView = findViewById(R.id.recycler_view);
          recyclerView.setLayoutManager(new LinearLayoutManager(NoteListActivity.this));
    
    }
    
    }
    

    更新说明

    public class AddNoteActivity extends AppCompatActivity {
    
        private TextInputEditText et_title,et_content;
        private NoteDatabase noteDatabase;
        private Note note;
        private boolean update;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_add_note);
            et_title = findViewById(R.id.et_title);
            et_content = findViewById(R.id.et_content);
            noteDatabase = NoteDatabase.getInstance(AddNoteActivity.this);
            Button button = findViewById(R.id.but_save);
            if ( (note = (Note) getIntent().getSerializableExtra("note"))!=null ){
                getSupportActionBar().setTitle("Update Note");
                update = true;
                button.setText("Update");
                et_title.setText(note.getTitle());
                et_content.setText(note.getContent());
            }
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                note.setContent(et_content.getText().toString());
                note.setTitle(et_title.getText().toString());
                noteDatabase.getNoteDao().updateNote(note);
                }
            });
        }
    
    }
    

    删除笔记

    noteDatabase.getNoteDao().deleteNote(notes.get(pos));
    adapterObj.notifyDataSetChanged();
    

    【讨论】:

      【解决方案2】:

      房间数据库

      • Room 是 Android 开发中 SQLite 数据库的 ORM(对象关系映射器),也是 Android Jetpack 的一部分。
      • 在 SQLite 数据库上提供抽象层
      • 样板代码量减少
      • SQL 查询的编译时验证

      ROOM 数据库组件

      • 它有 3 个主要组件 Entity、Database、DAO。
      • Entity是用@Entity注解的数据类,就像在SQLite中创建一个表,模型类中的变量就像表中的列。
      • Database 是一个抽象类,它扩展了 RoomDatabase 并具有与数据库关联的实体列表。
      • DAO(Data Access Object) 是一个定义要在我们的数据库中执行的操作的接口。

      ROOM 数据库实施

      • 第一步创建Entity数据类

        @Entity(tableName = "yourOwnTableName")

        数据类LocalData(

          val column1: String?,
        
          val column2: String?,  
        
          @PrimaryKey(autoGenerate = true) val product_local_id: Int?= null
        

        )

      • 第 2 步创建数据库

        @Database(entities = [LocalData::class], version = 1, exportSchema = false) @TypeConverters

        抽象类 LocalDB : RoomDatabase() {

          abstract fun localDataDao() : LocalDataDAO
        
          companion object{
        
              private var instance : LocalDB ? = null
        
              fun getInstance(context: Context) : LocalDB ?{
                  if(instance == null){
                      synchronized(LocalDB ::class){
                          instance = Room.databaseBuilder(context.applicationContext, LocalDB::class.java, "localBD.db").allowMainThreadQueries().build()
                      }
                  }
                  return instance
              }
        
              fun destroyInstance(){
                  instance = null
              }
          }
        

        }

      • 第 3 步创建 DAO

        @道 接口 LocalDAO {

          @Insert
          fun insertData(productEntity: LocalData) : Long
        
          @Delete
          fun deleteData(productEntity: LocalData) : Int
        
          @Query("Select * from yourOwnTableName")
          fun showAllProducts(): List<LocalData>
        
          @Query("SELECT COUNT(*) FROM yourOwnTableName")
          fun totalProducts(): Long
        

        }

      • 第 4 步是可选的,即创建 存储库

      类 ProductRepository(context: Context) {

      var dbms : LocalDAO = LocalDB.getInstance(context)?.localDataDao()!!
      
      fun insertData(productEntity: LocalData) : Long{
          return dbms.insertData(productEntity)
      }
      
      fun deleteData(productEntity: LocalData) : Int{
          return dbms.deleteData(productEntity)
      }
      
      fun getAllData() : List<LocalData> {
          return dbms.showAllProducts()
      }
      
      fun checkProductExist(id : Int) : Boolean{
          return dbms.exists(id)
      }
      
      fun totalProductsInCart() : Long{
          return dbms.totalProducts()
      }
      

      }

      【讨论】:

        【解决方案3】:

        咨询official documentation怎么样。

        【讨论】:

          【解决方案4】:

          我认为最好的地方是 codelabs,它有一个 simple 实现,还有一个更多 complex 一个。都在使用 Room。

          编辑:以上链接似乎已被删除。这里有一些资源可以替代它:

          1. Android room with a view
          2. Room + LiveData + ViewModel

          【讨论】:

          • 此回复中的链接今天不起作用
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-01-24
          • 2018-08-17
          • 2021-08-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多