你应该考虑把硬东西扔到数据库上。
考虑以下实体:
cardentity
that contains informations about special card.它还确保在单层中可以以给定的名称存在一张卡。
实体(
tablename=“卡”,
索引={
@索引(value=“name”,“deck”,unique=true)
}
)
公营级身份证{
//区域列定义
基本密钥
@columninfo(name=“id”)。
私人长ID;
@非空
@columninfo(name=“name”)。
私有字符串名称“”;
@非空
@columninfo(name=“deck_id”)
私人长甲板=0L;
/ /端部区域
//区域getter和setter
(…)
/ /端部区域
}
< /代码>
deckEntity
that contains informations about special deck.
@entity(tablename=“decks”)。
公共级甲板实体{
//区域列定义
基本密钥
@columninfo(name=“id”)。
私人长ID;
@非空
@columninfo(name=“name”)。
私有字符串名称“”;
/ /端部区域
//区域getter和setter
(…)
/ /端部区域
}
< /代码>
deckwithcardsviewis a projection that combined togetherdeckentity,collection ofcardentityand some metadata(在此情况下-a number of cards in this deck)..
public class deckwithcardsview{
/区域甲板
@嵌入式
私人甲板实体甲板;
public deckEntity getdeck()。{
返回甲板;
}
公共空隙设置甲板(甲板实体甲板){
this.deck=甲板;
}
/ /端部区域
/区域卡
@关系
实体=cardentity.class,
entitycolumn=“甲板_id”,
parentcolumn=“id”)。
private list<cardentity>cards=new arraylist<>();
公共列表<cardentity>getcards()。{
回程卡;
}
公共作废设置卡(列表<卡标识>卡){
this.cards=卡;
}
/ /端部区域
//区域卡计数
私有整数计数=0;
公共整数getCount()。{
返回计数;
}
公共void setcount(整数计数){
this.count=计数;
}
/ /端部区域
}
< /代码>
一个完整的daocode可以看起来像:
达奥> >代码> @
公共抽象类deckdao{
/区域甲板
@插入(onConflict=OnConflictStrategy.Ignore)
公共摘要void insertdeck(deckentity实体);
@插入(onConflict=OnConflictStrategy.Ignore)
public abstract void insertdecks(列出<deckEntity>实体);
/ /端部区域
/区域卡
@插入(onConflict=OnConflictStrategy.Ignore)
公共摘要作废插件卡(卡片实体);
@插入(onConflict=OnConflictStrategy.Ignore)
公共摘要作废插入卡(列表<卡标识>卡);
/ /端部区域
//带卡片的区域牌组
@交易
@查询
“选择d.id作为id,d.name作为name,count(c.id)作为count”
+“从甲板D”
+“内部连接卡C”
+“其中c.deck_id=d.id”
+“按甲板分组”
public abstract flowable<list<deckwithcardsview>>getall();
/ /端部区域
}
< /代码>
它实现了以下功能:
- 正在将单层添加到数据库中,
- 向数据库中添加一组数据包,
- 正在向数据库添加单卡,
- 将一组卡添加到数据库中,
- 从数据库中检索上述投影的列表。
-
最重要的部分是sqlite查询代码。逐行:
< Buff行情>
选择d.id作为id,d.name作为name,count(c.id)作为count
< /块引用>
它定义了查询将从数据库返回值的准确列。特别是:
d.id as id-它将返回idfrom column aliased asd(decks),,
d.name as name-它将返回namefrom column aliased asd(decks),,
count(c.id)as count-它将返回从别名为c的列中检索到的ID的数目。
< Buff行情>
从甲板D内部连接卡C,其中C.deck_id=D.id
< /块引用>
它定义了我们要从表中检索值deck saliased asdandcardsaliased ascand defines the relationship oncardentity'sdeck_idtodeckentityidcolumns.
< Buff行情>
按甲板分组
< /块引用>
由于分组,我们可以很容易地执行count(c.id)to retrieve a number of cards returned for every single deck.
因为我们还使用了@embeddedannotation indeckwithcardsview-corresponding(aliased)columns will be matched to correct fields in embeddeddeckentitydeck field.
数据库管理器
在准备好这些实体、投影和DAO之后,数据库管理器可以简单地实现如下:
public completeable savealldecks(@nullable list<deckEntity>decks){
返回Completeable.FromAction(
()->数据库
DekDoO()
.镶块(甲板)
.subscribeon(schedulers.io());
}
公共可完成的saveallcards(@nullable list<cardentity>卡){
返回Completeable.FromAction(
()->数据库
DekDoO()
.insertcards(卡)
.subscribeon(schedulers.io());
}
public flowable<list<deckwithcardsview>>getdeckwithcards()。{
返回数据库
DekDoO()
GET()
.subscribeon(schedulers.io());
}
< /代码>
示例数据:
我还准备了一个示例代码,创建了五个完整的甲板(每个甲板上的所有西装和军衔)。
private static final long[]甲板={
1升、2升、3升、4升、5升
};
私有静态最终字符串[]数据包名称={
“甲板1”,“甲板2”,“甲板3”,“甲板4”,“甲板5”
};
completeTable PreparedEcks()。{
final observable<long>ids=observable.fromarray(deck_ids);
final observable<string>name=observable.fromarray(甲板名称);
最终列表<deckEntity>decks=ids.flatmap(id->name.map(name->){
final deckEntity实体=new deckEntity();
实体.setid(id);
entity.setname(名称);
返回实体;
}).tolist().blockingget();
返回cinemamanager.savedecks(甲板);
}
< /代码>
它创建一个ID和数据组名称的列表,并创建此类表的产品。平面映射这样的产品会产生一个完整的五层实体列表。
private static final string[]卡套装={
“钻石”、“红心”、“黑桃”、“梅花”
};
私有静态最终字符串[]卡\排名={
“两个”,
“三”
“四”
“五”
“六”
“七”
“八”
“九”
“十”
“杰克”
“女王”
“国王”
“王牌”
};
可完成的PrepareCards()。{
final observable<long>decks=observable.fromarray(deck_id);
final observable<string>suits=observable.fromarray(卡片套装);
final observable<string>ranks=observable.fromarray(卡片排名);
最终列表<cardentity>cards=decks.flatmap(deck->suits.flatmap(suit->ranks.map(rank->){
final cardentity entity=新cardentity();
entity.setname(string.format(“%s%s”,rank,suit));
实体。setdeckid(deck);
返回实体;
})).tolist().blockingget();
返回cinemamanager.savecards(卡);
}
< /代码>
使用类似的方法,我已经为以前准备好的牌组创建了一个完整的卡片集合。
最后润色:
艰苦的工作已经完成了。剩下的简单部分:
private completeable preparedata()。{
返回PreparedEcks(),然后返回(PrepareCards());
}
void observedeck swithcards()。{
可处置物品。添加(
准备数据()
.andthen(deckmanager.getdeckswithcards())
.observeon(AndroidSchedulers.mainthread())
订阅(
这是:handleobservedeck的swithcardssuccess,
此::handleObserveDeck swithCardsError));
}
private void handleobservedeck swithcardssuccess(@nonnull list<deckwithcardsview>decks){
timber.v(“接收的甲板数:%d”,decks.size());
}
private void handleObserveDeck swithCardsError(@nonnull throwable throwable){
timber.e(throwable.getLocalizedMessage());
}
< /代码>
结果:
结果我们有两张桌子。用于甲板和卡片。订阅getdeckswithcardsgives access to a collection of decks.有完整的卡片集合和卡片数量(按数据库计算)。

< Buff行情>
记住-由于已经建立了与带有卡片的表的关系,因此不需要使用countsqlite方法。您只需使用getcards().getsize()indeckwithcardsviewprojection。这将大大简化代码。
< /块引用>
有关特定卡的信息。它还可以确保在一个牌组中以给定的名称存在一张牌。
@Entity(
tableName = "cards",
indices = {
@Index(value = { "name", "deck_id" }, unique = true)
}
)
public class CardEntity {
//region Column Definitions
@PrimaryKey
@ColumnInfo(name = "id")
private Long id;
@NonNull
@ColumnInfo(name = "name")
private String name = "";
@NonNull
@ColumnInfo(name = "deck_id")
private Long deckId = 0L;
//endregion
//region Getters and Setters
(...)
//endregion
}
DeckEntity包含关于特定甲板的信息。
@Entity(tableName = "decks")
public class DeckEntity {
//region Column Definitions
@PrimaryKey
@ColumnInfo(name = "id")
private Long id;
@NonNull
@ColumnInfo(name = "name")
private String name = "";
//endregion
//region Getters and Setters
(...)
//endregion
}
DeckWithCardsView是将两者结合在一起的投影甲板实体收藏卡片实体以及一些元数据(在本例中是指这一组中的一些卡片)。
public class DeckWithCardsView {
//region Deck
@Embedded
private DeckEntity deck;
public DeckEntity getDeck() {
return deck;
}
public void setDeck(DeckEntity deck) {
this.deck = deck;
}
//endregion
//region Cards
@Relation(
entity = CardEntity.class,
entityColumn = "deck_id",
parentColumn = "id")
private List<CardEntity> cards = new ArrayList<>();
public List<CardEntity> getCards() {
return cards;
}
public void setCards(List<CardEntity> cards) {
this.cards = cards;
}
//endregion
//region Cards count
private Integer count = 0;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
//endregion
}
完整的Dao代码可以是:
@Dao
public abstract class DeckDao {
//region Deck
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void insertDeck(DeckEntity entity);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void insertDecks(List<DeckEntity> entities);
//endregion
//region Card
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void insertCard(CardEntity entity);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract void insertCards(List<CardEntity> cards);
//endregion
//region Deck with Cards
@Transaction
@Query(
"SELECT D.id as id, D.name as name, count(C.id) as count "
+ "FROM decks D "
+ "INNER JOIN cards C "
+ "WHERE C.deck_id = D.id "
+ "GROUP BY deck_id")
public abstract Flowable<List<DeckWithCardsView>> getAll();
//endregion
}
它实现了以下功能:
- 向数据库中添加单层,
- 向数据库中添加一组数据包,
- 向数据库添加单卡,
- 向数据库中添加一组卡片,
- 从数据库中检索上述投影的列表。
最重要的部分是sqlite查询代码。逐行:
选择d.id作为id,d.name作为name,count(c.id)作为count
它定义了查询将从数据库返回值的准确列。特别是:
D.id as id-它会回来的id从别名为的列D(甲板)
D.name as name-它会回来的name从别名为的列D(甲板)
count(C.id) as count-它将返回从别名为C(卡片)。
从甲板D内部连接卡C,其中C.deck_id=D.id
它定义了我们要从表中检索值decks别名为D和cards别名为C定义关系卡片实体的deck_id到甲板实体的身份证件柱。
按甲板分组
由于分组,我们很容易做到count(C.id)为每一个牌组检索返回的卡片数。
因为我们也用了@Embedded注释带卡视图的甲板-相应的(别名)列将与嵌入的正确字段匹配甲板实体甲板场
数据库管理器
在准备好这些实体、投影和DAO之后,数据库管理器可以简单地实现如下:
public Completable saveAllDecks(@Nullable List<DeckEntity> decks) {
return Completable.fromAction(
() -> database
.deckDao()
.insertDecks(decks)
).subscribeOn(Schedulers.io());
}
public Completable saveAllCards(@Nullable List<CardEntity> cards) {
return Completable.fromAction(
() -> database
.deckDao()
.insertCards(cards)
).subscribeOn(Schedulers.io());
}
public Flowable<List<DeckWithCardsView>> getDecksWithCards() {
return database
.deckDao()
.getAll()
.subscribeOn(Schedulers.io());
}
实例数据:
我还准备了一个示例代码,创建了五个完整的甲板(每个甲板上的所有西装和军衔)。
private static final Long[] DECK_IDS = {
1L, 2L, 3L, 4L, 5L
};
private static final String[] DECK_NAMES = {
"Deck 1", "Deck 2", "Deck 3", "Deck 4", "Deck 5"
};
Completable prepareDecks() {
final Observable<Long> ids = Observable.fromArray(DECK_IDS);
final Observable<String> names = Observable.fromArray(DECK_NAMES);
final List<DeckEntity> decks = ids.flatMap(id -> names.map(name -> {
final DeckEntity entity = new DeckEntity();
entity.setId(id);
entity.setName(name);
return entity;
})).toList().blockingGet();
return cinemaManager.saveDecks(decks);
}
它创建一个ID和数据组名称的列表,并创建此类表的产品。平面映射这样的产品会产生一个完整的五层实体列表。
private static final String[] CARD_SUITS = {
"diamonds", "hearts", "spades", "clubs"
};
private static final String[] CARD_RANKS = {
"Two of ",
"Three of ",
"Four of ",
"Five of ",
"Six of ",
"Seven of",
"Eight of ",
"Nine of ",
"Ten of ",
"Jack of ",
"Queen of ",
"King of ",
"Ace of "
};
Completable prepareCards() {
final Observable<Long> decks = Observable.fromArray(DECK_IDS);
final Observable<String> suits = Observable.fromArray(CARD_SUITS);
final Observable<String> ranks = Observable.fromArray(CARD_RANKS);
final List<CardEntity> cards = decks.flatMap(deck -> suits.flatMap(suit -> ranks.map(rank -> {
final CardEntity entity = new CardEntity();
entity.setName(String.format("%s %s", rank, suit));
entity.setDeckId(deck);
return entity;
}))).toList().blockingGet();
return cinemaManager.saveCards(cards);
}
使用类似的方法,我为以前准备的牌组创建了一个完整的卡片集合。
最后的接触:
艰苦的工作已经完成了。最简单的部分是:
private Completable prepareData() {
return prepareDecks().andThen(prepareCards());
}
void observeDecksWithCards() {
disposables.add(
prepareData()
.andThen(deckManager.getDecksWithCards())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
this::handleObserveDecksWithCardsSuccess,
this::handleObserveDecksWithCardsError));
}
private void handleObserveDecksWithCardsSuccess(@NonNull List<DeckWithCardsView> decks) {
Timber.v("Received number of decks: %d", decks.size());
}
private void handleObserveDecksWithCardsError(@NonNull Throwable throwable) {
Timber.e(throwable.getLocalizedMessage());
}
结果:
结果我们有两张桌子。用于甲板和卡片。订阅getDecksWithCards允许访问甲板集合。有完整的卡片收集和卡片数量(按数据库计算)。

记住-由于与卡片表的关系已经建立,因此您不需要使用countSQLite方法。你可以用getCards().getSize()在里面带卡视图的甲板投影。这将大大简化代码。