手摸手教你在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>