Room中List<>使用詳解

手摸手教你在Room中使用List<Object>.

實際項目有很多這樣的結構:

{
  "id": "001",
  "name": "王誅魔",
  "age": 2018,
  "books": [
    {
      "bookId": 10081,
      "userId": 1,
      "book": "斷罪小學",
      "desc": "漫畫講述了李殺神漂洋、王誅魔和劉斬仙三位少年遥皂,為了十萬小學生的未來、為了改變被詛咒的命運氮发,相聚在狼牙區(qū)飛虎路私立斷罪小學渴肉,誓死打敗四年級的魔神趙日天的故事。"
    },
    {
      "bookId": 10088,
      "userId": 1,
      "book": "狂霸天下之斷罪學園",
      "desc": "《狂霸天下之斷罪學園》爽冕,后來因為名字太長仇祭,而且“學園”和“學院”容易混淆的原因而改名。"
    }
  ]
}

也就是,類似books這樣的,List<Object>作為一個元素存在.

下面就以上面的結構為例,做一個簡單的演示,按照最簡答的方法實現(xiàn).

1.添加依賴

https://developer.android.google.cn/topic/libraries/architecture/adding-components.html

值得注意的是,如果你在kotlin中使用

apply plugin: 'kotlin-kapt'
...
dependencies{
  
  ...
    //這個無法生成代碼,要用下面的那一條,不要疏忽忘掉了.
    //annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
    
    kapt "android.arch.persistence.room:compiler:1.0.0"
}

一定記得使用kapt,要不然就會遇到這個BUG.

2.創(chuàng)建表

  • User.java表

    /**
     * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
     * @author 王誅魔 2018/1/3 下午1:31
     */
    @Entity(tableName = "users")
    public class User {
        @PrimaryKey
        public int id;
        public String name;
        public int age;
    }
    

    @Entity 中指定了表名

    @PrimaryKey 主鍵

    這張表users 用于保存用戶數(shù)據(jù)

  • Book.java表

    /**
     * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
     * @author 王誅魔 2018/1/3 下午1:30
     */
    @Entity(foreignKeys = {
            @ForeignKey(
                    entity = User.class,
                    parentColumns ={"id"},
                    childColumns = {"userId"})
    },tableName = "books")
    public class Book {
        @PrimaryKey
        public int bookId;
        public int userId;//同User.java中的id
        public String book;
        public String desc;
    
    }
    

    @Entity 中

    • foreignKeys = {} 中外鍵,可以是多個,這里只關聯(lián)了User表
    • tableName = "books" 指定了表名

    @PrimaryKey 該表主鍵

    ?

    ?

  • UserAndBook.java表 ----UserAndBook只是輔助,不作為一張表存在.

    /**
     * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
     * @author 王誅魔 2018/1/3 下午1:43
     */
    public class UserAndBook {
        @Embedded   //請看之前的文章,這是指把User中所有元素帶入到這里作為元素存在
        public User userEntity;
    
          //@Relation
        @Relation(parentColumn = "id",entityColumn = "userId",entity = Book.class)
        public List<Book> books;
    
    }
    
    

    @Embedded 請看另一篇,有解釋

    ?

    @Relation 點這里去看官方文檔

    A convenience annotation which can be used in a Pojo to automatically fetch relation entities. When the Pojo is returned from a query, all of its relations are also fetched by Room.

    個人以為就是一注解,指明關系,可以把實體關聯(lián)起來,然后自動組裝起來.

    ?

    并且在文檔中還展示了一種高端的功能,用上面做例

    //@Relation
        @Relation(parentColumn = "id",entityColumn = "userId",
                  entity = Book.class ,projection = {"book"})
        public List<String> bookNames;
    

    解釋一下,projection指定了要取出的值,當前指明要在 books表中尋找符合條件parentColumn = "id",entityColumn = "userId" 的項,找到之后會拿到book這個值并返回.

3.Dao實現(xiàn)

/**
 * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
 * @author 王誅魔 2018/1/3 下午4:20
 */
@Dao
public abstract class UserAndBookDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public abstract void insert(User user);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public abstract void insert(List<Book> books);

    @Transaction
    public void insert(UserAndBook userAndBook){
        insert(userAndBook.userEntity);
        insert(userAndBook.books);
    }
  
    @Query("SELECT * FROM users")
    public abstract List<UserAndBook> getAll();
}

insert(User user); ,insert(List<Book> books);

兩個方法,也可以私有化,只對外提供insert(UserAndBook userAndBook)

最近換公司項目的數(shù)據(jù)庫,用sql,真的有意思,可以很方便的實現(xiàn)很多功能

4.建立數(shù)據(jù)庫

/**
 * If you have any questions, you can contact by email { wangzhumoo@gmail.com}
 * @author 王誅魔 2017/10/24 上午10:13
 * 數(shù)據(jù)庫
 */
@Database(entities = {Book.class, User.class}, 
          version = 1, exportSchema = false)
public abstract class AppDB extends RoomDatabase {
    private static final String TAG = "AppDB";

    /**
     * 數(shù)據(jù)庫實例
     */
    private static AppDB sInstance;
    private static String DATABASE_NAME = "developer.db";
    private ObservableBoolean mIsDatabaseCreated = new ObservableBoolean(false);

    
    public abstract UserAndBookDao userbook();

    /**
     * 單例
     * @param context
     * @return
     */
    public static AppDB getInstance(Context context) {
        if (sInstance == null) {
            synchronized (AppDB.class) {
                if (sInstance == null) {
                    sInstance = buildDatabase(context);
                    sInstance.updateDatabaseCreated(context);
                }
            }
        }
        return sInstance;
    }

    /**
     * Build the database.
     * creates a new instance of the database.
     */
    private static AppDB buildDatabase(Context appContext) {
         AppDB appDB = Room.databaseBuilder(appContext, AppDB.class, DATABASE_NAME)
                .addCallback(new Callback() {
                    @Override
                    public void onCreate(@NonNull SupportSQLiteDatabase db) {
                        super.onCreate(db);
                        AppDB database = AppDB.getInstance(appContext);
                        database.setDatabaseCreated();
                    }

                    @Override
                    public void onOpen(@NonNull SupportSQLiteDatabase db) {
                        super.onOpen(db);
                        Log.e(TAG, "onOpen: " + db.getPath());
                    }
                }).build();

        return appDB;
    }

    /**
     * Check whether the database already exists and expose it via 
     */
    private void updateDatabaseCreated(final Context context) {
        if (context.getDatabasePath(DATABASE_NAME).exists()) {
            setDatabaseCreated();
        }
    }

    private void setDatabaseCreated() {
        mIsDatabaseCreated.set(true);
    }

    public ObservableBoolean getDatabaseCreated() {
        return mIsDatabaseCreated;
    }
}

為了方便使用,在Application中添加了

public static AppDB getDatabase() {
    return AppDB.getInstance(context);
}

5.使用

這里的使用方式,不建議使用,太粗暴了.

可以學學Demo,Google出的googlesamples/android-architecture-components

class RoomActivity : BindingActivity<ActivityRoomBinding, RoomViewModel>() {
    val gson = Gson()

    override fun getBundle(extras: Bundle) {
    }

    override fun layoutID(): Int = R.layout.activity_room

    override fun initViews(savedInstanceState: Bundle?) {
        
        //點擊事件  ADD按鈕,添加數(shù)據(jù)到數(shù)據(jù)庫
        mBindingView.button.setOnClickListener({
            val userBook = UserAndBook()
            val jsonStr = FileUtils.getJson(this, "data.txt")
            val objectJson = JsonParser().parse(jsonStr).asJsonObject

            //獲取用戶
            val user = objectJson.get("user")
            userBook.userEntity = gson.fromJson<User>(user, User::class.java)

            //保存用戶
            Observable
                .empty<Any>()
                .observeOn(Schedulers.io())
                .subscribe(object : EmptyObserver<Any?>() {
                    override fun onComplete() {
                        App.getDatabase().userbook().insert(userBook.userEntity)
                    }
                })

            //獲取書籍
            val books = objectJson.get("books")
            userBook.books = gson.fromJson<ArrayList<Book>>
                                (books, object : TypeToken<List<Book>>() {}.type)
            //保存書籍
            Observable
                .empty<Any>()
                .observeOn(Schedulers.io())
                .subscribe(object : EmptyObserver<Any?>() {
                     override fun onComplete() {
                        App.getDatabase().userbook().insert(userBook.books)
                    }
                })
        })


        //點擊事件,按鈕QUERY   查詢數(shù)據(jù)
        mBindingView.button2.setOnClickListener {
            Flowable.create(FlowableOnSubscribe<List<UserAndBook>> { e ->
                val userBook = App.getDatabase().userbook().all
                e.onNext(userBook)
                e.onComplete()
            }, BackpressureStrategy.DROP)
                    .compose(DatabaseTransformer())
                    .subscribe(object : DatabaseSubscriber<List<UserAndBook>>() {
                        override fun onNext(userAndBooks: List<UserAndBook>) {
                            mBindingView.data = userAndBooks[0]
                        }
                    })
        }

    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.wangzhumo.app.data.UserAndBook"/>
        <import type="com.wangzhumo.app.data.User"/>
        <import type="com.wangzhumo.app.data.Book"/>
        <variable
            name="data"
            type="com.wangzhumo.app.data.UserAndBook"/>
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="57dp"
            android:layout_marginStart="57dp"
            android:layout_marginTop="125dp"
            android:text="Add" />

        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBaseline="@+id/button"
            android:layout_alignBottom="@+id/button"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_marginEnd="56dp"
            android:layout_marginRight="56dp"
            android:text="Query" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/button"
            android:layout_marginTop="68dp">

            <TextView
                android:id="@+id/textView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_marginLeft="36dp"
                android:layout_marginStart="36dp"
                android:layout_marginTop="32dp"
                android:text="@{data.userEntity.name}" />

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView"
                android:layout_alignStart="@+id/textView"
                android:layout_below="@+id/textView"
                android:layout_marginTop="41dp"
                android:text="@{data.books.get(0).book}" />

            <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignLeft="@+id/textView2"
                android:layout_alignStart="@+id/textView2"
                android:layout_centerVertical="true"
                android:text="@{data.books.get(0).desc}" />
        </RelativeLayout>
    </RelativeLayout>
</layout>

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末颈畸,一起剝皮案震驚了整個濱河市乌奇,隨后出現(xiàn)的幾起案子没讲,更是在濱河造成了極大的恐慌,老刑警劉巖礁苗,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爬凑,死亡現(xiàn)場離奇詭異,居然都是意外死亡试伙,警方通過查閱死者的電腦和手機嘁信,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疏叨,“玉大人潘靖,你說我怎么就攤上這事≡槁” “怎么了卦溢?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秀又。 經(jīng)常有香客問我单寂,道長,這世上最難降的妖魔是什么吐辙? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任宣决,我火速辦了婚禮,結果婚禮上袱讹,老公的妹妹穿的比我還像新娘疲扎。我一直安慰自己昵时,他們只是感情好捷雕,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著壹甥,像睡著了一般救巷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上句柠,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天浦译,我揣著相機與錄音,去河邊找鬼溯职。 笑死精盅,一個胖子當著我的面吹牛,可吹牛的內容都是我干的谜酒。 我是一名探鬼主播叹俏,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼僻族!你這毒婦竟也來了粘驰?” 一聲冷哼從身側響起屡谐,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝌数,沒想到半個月后愕掏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡顶伞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年饵撑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆貌。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡肄梨,死狀恐怖,靈堂內的尸體忽然破棺而出挠锥,到底是詐尸還是另有隱情众羡,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布蓖租,位于F島的核電站粱侣,受9級特大地震影響,放射性物質發(fā)生泄漏蓖宦。R本人自食惡果不足惜齐婴,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望稠茂。 院中可真熱鬧柠偶,春花似錦、人聲如沸睬关。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽电爹。三九已至蔫仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丐箩,已是汗流浹背摇邦。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屎勘,地道東北人施籍。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像概漱,于是被迫代替她去往敵國和親丑慎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)立哑,斷路器夜惭,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的閱讀 13,470評論 5 6
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法铛绰,內部類的語法诈茧,繼承相關的語法,異常的語法捂掰,線程的語...
    子非魚_t_閱讀 31,622評論 18 399
  • 配置 修改config/database.php在connection數(shù)組中添加mongodb的配置信息敢会,如下 '...
    jooohnny閱讀 8,430評論 3 8
  • 一. Java基礎部分.................................................
    wy_sure閱讀 3,810評論 0 11