【问题标题】:Android Room Generic DAOAndroid Room 通用 DAO
【发布时间】:2018-08-25 14:43:24
【问题描述】:

美好的一天 Stack,我正在开发一个使用 Android 的 Room 1.0.0 Alpha 5 的 Android 项目,我面临的主要问题是每次我需要从房间调用一个 DAO 时,我需要做这样的事情:

Activity.java:

...
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "Storage").build();
Table1 table = new Table1();
table.setId(1);
table.setName("Hello");
new AccessDB().execute(1);

/* Generic AccessDB needed */
private class AccessDB extends AsyncTask<Integer,Void,List<Table1>> {

    @Override
    protected List<Table1> doInBackground(Integer... param) {
        switch(param[0]) {
            case 1:
                return db.Table1DAO().create();
            case 2:
                return db.Table1DAO().read();
        }
        return new ArrayList<>();
    }

    @Override
    protected void onPostExecute(List<Table1> list) {
        processData(list);
    }
}
...

我知道我可以从主线程访问 Room DB,这会缩减代码,但我认为这不是一个好习惯,因为这会在每次必须处理数据时锁定活动。

因此,如果我需要从“Table2”插入或读取数据,我将不得不重新做同样的事情,如果我可以将实体类型转换为“T”之类的泛型或类似的东西,那就太好了制作一个通用的“AccessDB”。 但由于我对 Java 不太熟悉......我目前正在努力解决这个问题。

这是实例的一些其他代码。

AppDatabase.java:

@Database(entities = {Table1.class, Table2.class, Table3.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract Table1DAO Table1DAO();
    public abstract Table2DAO Table2DAO();
    public abstract Table3DAO Table3DAO();
}

Table1.java:

@Entity
public class Table1 {
    /* setters & getters */
    @PrimaryKey(autoGenerate = true)
    private int id;
    private String name;
}

Table1DAO.java:

@Dao public interface Table1DAO {
    @Query("SELECT * FROM Table1")
    List<Table1> read(Table1 table);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    List<Long> create(Table1... table);
}

感谢大家的帮助。

【问题讨论】:

    标签: java android android-asynctask dao android-room


    【解决方案1】:

    您可以使用继承并创建一个BaseDao,它将由您的所有孩子Dao 实现。这样您就不需要一次又一次地编写常用方法。

    interface BaseDao<T> {
    
    /**
     * Insert an object in the database.
     *
     * @param obj the object to be inserted.
     */
    @Insert
    fun insert(obj: T)
    
    /**
     * Insert an array of objects in the database.
     *
     * @param obj the objects to be inserted.
     */
    @Insert
    fun insert(vararg obj: T)
    
    /**
     * Update an object from the database.
     *
     * @param obj the object to be updated
     */
    @Update
    fun update(obj: T)
    
    /**
     * Delete an object from the database
     *
     * @param obj the object to be deleted
     */
    @Delete
    fun delete(obj: T)
    }
    

    了解更多信息:https://gist.github.com/florina-muntenescu/1c78858f286d196d545c038a71a3e864#file-basedao-kt

    Florina 的原创作品。

    【讨论】:

    • 我想到了一个很相似的东西,不过我觉得这样更好,好像也不能有默认查询,但是还是很有帮助的。
    • 我只看到 Kotlin 中 Dao 的继承。它也可以在 Java 中工作,不是吗?
    • 是的,它也适用于 Java;因为 Java 支持继承。
    【解决方案2】:

    我对 Akshay Chordiya 的答案进行了一些尝试,但需要添加两个:

    • 能够插入/更新列表
    • 返回值以监控插入/更新是否成功

    这是我想出的:

    import androidx.room.Dao
    import androidx.room.Insert
    import androidx.room.OnConflictStrategy
    import androidx.room.Update
    
    /**
     * List of all generic DB actions
     * All use suspend to force kotlin coroutine usage, remove if not required
     */
    @Dao
    interface BaseDao<T> {
    
        // insert single
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        suspend fun insert(obj: T?): Long
    
        // insert List
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        suspend fun insert(obj: List<T>?) : List<Long>
    
        // update List
        @Update
        suspend fun update(obj: List<T>?): Int
    
    }
    

    @Dao
    interface MyObjectDao : BaseDao<MyObject> {
    
        @Query("SELECT * from $TABLE_NAME WHERE $COL_ID = :id")
        suspend fun getById(id: Long): MyObject
    
    }
    

    然后可以这样调用:

    val ids = MyObjectDao.insert(objectList)
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-09
    • 2018-04-19
    • 2018-06-18
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    相关资源
    最近更新 更多