Каков наилучший способ хранения Arraylists в Комнате, зная, что я хочу, чтобы не только один Arraylist приходил?
Возможно, нет лучшего пути.
ArrayList не просто появляются, данные и структура элемента (если существует несколько значений на элемент) откуда-то, то есть они являются просто контейнерами, а не постоянными контейнерами сгруппированных данных.Поскольку конечный результат, по-видимому, представляет собой устойчивые структурированные наборы данных, вероятно, было бы проще в первую очередь использовать базу данных.
Я пытаюсь построить Deckbuilder для карточной игры.Различные колоды основаны на одном Arraylists, которые я хочу сохранить локально.
Звучит так, будто это база карт, то есть карт, доступных для игры.Похоже, вам нужна таблица в базе данных для карт .
Это означает, что вы можете создать свою колоду, и тогда я хочу, чтобы вы смогли ее сохранить, изатем создайте новую колоду,
Звучит так, как будто вам нужна таблица в базе данных для колод и что в колоде может быть список карт.Так сколько карт?10, 20, 3000?Хорошо, если вы используете возможности отношений Realtional Database Manager (который SQLite и, следовательно, Room (так как последний является абстрактным слоем над SQLite)).Таким образом, вполне вероятно, что то, что известно как таблица сопоставления (ссылки, отношения и другие имена для одной и той же вещи).
Это в первую очередь хранит отношения, которые состоят из столбца, который может идентифицировать одну часть отношения идругой столбец, который может идентифицировать другую часть.Примените это к вашему случаю, когда DECK будет иметь отношение к нескольким картам, CARD может появиться в нескольких DECK.Это много-много отношений, которые обслуживает таблица сопоставления.Поэтому вам, вероятно, понадобится таблица mapping .
В качестве основы для дальнейших объяснений предполагается, что речь идет об игральных картах (Ace of Spades, Queen of Hearts и так далее).
Итак, нам нужны три таблицы: таблица Card , таблица Deck и таблица, которая отображает карты в колоды (и, следовательно, наоборот), Card_Deck_MapТаблица .
Таблица Card для простоты будет иметь один столбец для имя карты .Таблицы Deck будут иметь один столбец для deckname . Для эффективности будет использован идентификатор, который является псевдонимом специального столбца rowid .Таким образом, в каждой из приведенных выше таблиц будет дополнительный столбец, который будет называться _id (при названии столбца _id это может быть полезно для Android).
Это будетПредполагается, что вы не хотите, чтобы имя карты или название колоды дублировались, и поэтому будут применены УНИКАЛЬНЫЕ ограничения, которые не позволят дублировать имена.
Чтобы сократить все, вот как этоможет выглядеть в SQL (что, в конечном счете, делает большинство операций по хранению, обработке и извлечению данных): -
-- Delete the tables if they exist (just in case)
DROP TABLE IF EXISTS card_deck_map;
DROP TABLE IF EXISTS card;
DROP TABLE IF EXISTS deck;
-- Create the tables
CREATE TABLE IF NOT EXISTS card (_id INTEGER PRIMARY KEY, cardname UNIQUE);
CREATE TABLE IF NOT EXISTS deck (_id INTEGER PRIMARY KEY, deckname UNIQUE);
CREATE TABLE IF NOT EXISTS card_deck_map (
card_reference INTEGER REFERENCES card(_id),
deck_reference INTEGER REFERENCES deck(_id),
PRIMARY KEY(card_reference,deck_reference)
);
-- Add 3 cards to the card table
INSERT INTO card (cardname) VALUES ('CARD001'),('CARD002'),('CARD003');
-- Add 3 decks to the deck table
INSERT INTO deck (deckname) VALUES ('DECK001'),('DECK002');
-- Create some mapping entries (aka put some cards into each deck)
INSERT INTO card_deck_map VALUES
(1,2), -- _id value for CARD001 should be 1, _id value for DECK002 should be 2
(3,2), -- CARD003 is in DECK002
(2,1), -- CARD002 is in DECK001
(1,1) -- CARD001 is also in DECK002
;
-- Have a look at what we have (ignore the id values they mean little to the user)
SELECT deckname, cardname
FROM deck
JOIN card_deck_map ON deck._id = deck_reference
JOIN card ON card_deck_map.card_reference = card._id
ORDER BY deckname, cardname
;
Вывод из приведенного выше будет: -
Итак, теперь дизайн базы данных подходит, а затем ее можно преобразовать для использования в ROOM.
Сначала 3 объекта Определение данных с использованием объектов Room
Card.java
: -
@Entity (indices = {@Index(value = {"cardname"}, unique = true)})
public class Card {
@PrimaryKey(autoGenerate = true)
public long _id;
@ColumnInfo(name = "cardname")
public String cardname;
}
Deck.java
: -
@Entity(indices = {@Index(value = "deckname", unique = true)})
public class Deck {
@PrimaryKey(autoGenerate = true)
public long _id;
@ColumnInfo(name = "deckname")
public String deckname;
}
Card_Deck_Map.java
: -
@Entity(
primaryKeys = {"card_reference","deck_reference"},
foreignKeys = {
@ForeignKey(entity = Card.class,parentColumns = "_id",childColumns = "card_reference"),
@ForeignKey(entity = Deck.class, parentColumns = "_id",childColumns = "deck_reference")}
)
public class Card_Deck_Map {
@ColumnInfo (name="card_reference")
public long card_reference;
@ColumnInfo(name="deck_reference")
public long deck_reference;
}
Теперь вам нужны определения объектов доступа к данным Accessing данные с использованием комнатных DAO
DeckBuildeDao
: -
@ открытый интерфейс Dao DeckBuilderDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] insertCards(Card... cards);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long insertCard(Card card);
@Update
public int updateCardBaseEntries(Card... cards);
@Update
public int updateCardBaseEntry(Card card);
@Delete
public int deleteCardBaseEntried(Card... cards);
@Delete
public int deleteCardBaseEntry(Card card);
@Query("SELECT * FROM card")
public Card[] getAllCards();
@Query("SELECT * FROM card WHERE _id = :id")
public Card getACard(long id);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] insertDecks(Deck... decks);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long insertDeck(Deck deck);
@Update
public int updateDeckEntries(Deck... decks);
@Update
public int updateDeckEntry(Deck deck);
@Delete
public int deleteDeckEntries(Deck... decks);
@Delete
public int deleteDeckEntry(Deck deck);
@Query("SELECT * FROM deck")
public int getAllDecks();
@Query("SELECT * FROM deck WHERE _id = :id")
public Deck getADeck(long id);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long[] addCardDeckEntries(Card_Deck_Map... cardDeckMaps);
@Insert(onConflict = OnConflictStrategy.IGNORE)
public long addCardDeckEntry(Card_Deck_Map cardDeckMap);
@Query("SELECT Deck._id,Card.cardname, Deck.deckname " +
"FROM deck " +
"JOIN card_deck_map ON deck._id = card_deck_map.deck_reference " +
"JOIN card ON card_deck_map.card_reference = card._id " +
"ORDER BY deckname, cardname")
public Cursor getAllDecksWithCards();
}
Класс для базы данных, который связывает сущности и DAO вместе
DeckBuilderDatabase.java
: -
@Database(entities = {Card.class, Deck.class, Card_Deck_Map.class}, version = 1)
public abstract class DeckBuilderDatabase extends RoomDatabase {
public abstract DeckBuilderDao deckBuilderDao();
}
Теперь действие, которое использует базу данных.
В этом рабочем примере;
база данных будет заполнена двумя колодами (Deck001 и Deck002) с карточной базой, как на колоду игральных карт, кроме джокеров.
- Карты будут называться как Ace of Spades, 2 of Hearts.
В колоды будут загружены некоторые карты (отображение)
- Deck002 со всеми 52 картами.
- Deck001 с3 карты.
Колоды и карты будут извлечены из базы данных и использованы для заполнения ListView.
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String[] SUITS = new String[]{"Spades","Hearts","Clubs","Diamons"};
public static final int CARDS_IN_A_SUIT = 13;
DeckBuilderDatabase mDBDB;
SimpleCursorAdapter mSCA;
ListView mDecks_and_Cards_List;
Cursor mCursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDecks_and_Cards_List = this.findViewById(R.id.decksandcards);
mDBDB = Room.databaseBuilder(this,DeckBuilderDatabase.class,"deckbuilder.db").build();
populateDB();
}
/**
* Populate the DB with some data, extract the data in the DB and setup the ListView
*/
private void populateDB() {
new Thread(new Runnable() {
@Override
public void run() {
Card_Deck_Map currentcdm = new Card_Deck_Map();
Deck[] decks_to_add = new Deck[]{new Deck(), new Deck()};
decks_to_add[0].deckname = "DECK001";
decks_to_add[1].deckname= "DECK002";
mDBDB.deckBuilderDao().insertDecks(decks_to_add);
// Build Card base pack of 52 (no Jokers)
Card[] cardstoadd = new Card[CARDS_IN_A_SUIT * SUITS.length];
int counter = 0;
for (int suit = 0; suit < SUITS.length; suit++) {
for (int cardval = 0; cardval < CARDS_IN_A_SUIT; cardval++) {
Card thiscard = new Card();
String thiscardname = generateCardValueDescription(cardval+1,suit);
thiscard.cardname = thiscardname;
cardstoadd[counter++] = thiscard;
}
}
mDBDB.deckBuilderDao().insertCards(cardstoadd);
// Populate the decks with cards Deck002 has full pack of 52 Deck001 has 3 cards
Card_Deck_Map[] mappings = new Card_Deck_Map[55];
for (int cardid = 1; cardid < 53; cardid++) {
Card_Deck_Map cdm = new Card_Deck_Map();
cdm.deck_reference = 2;
cdm.card_reference = cardid;
mappings[cardid-1] = cdm;
}
Card_Deck_Map cdm53 = new Card_Deck_Map();
cdm53.card_reference = 19;
cdm53.deck_reference = 1;
mappings[52] = cdm53;
Card_Deck_Map cdm54 = new Card_Deck_Map();
cdm54.card_reference = 10;
cdm54.deck_reference = 1;
mappings[53] = cdm54;
Card_Deck_Map cdm55 = new Card_Deck_Map();
cdm55.card_reference = 23;
cdm55.deck_reference = 1;
mappings[54] = cdm55;
mDBDB.deckBuilderDao().addCardDeckEntries(mappings);
// Get the Decks and cards in the decks
mCursor = mDBDB.deckBuilderDao().getAllDecksWithCards();
setupOrRefeshListView();
}
}).start();
}
/**
* Handles the ListView (also write data to the log for debugging)
*/
private void setupOrRefeshListView() {
int rowcount = mCursor.getCount();
Log.d("ROWS","Number of rows in the Cursor is " + String.valueOf(rowcount));
while (mCursor.moveToNext()) {
Log.d(
"ROWS",
"Row " +
String.valueOf(mCursor.getPosition()) +
" Has a deck called " +
mCursor.getString(mCursor.getColumnIndex("deckname")) +
" and a card called " +
mCursor.getString(mCursor.getColumnIndex("cardname"))
);
}
if (mSCA == null) {
mSCA = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2,
mCursor,
new String[]{
"deckname",
"cardname"},
new int[]{
android.R.id.text1,
android.R.id.text2},
0
);
mDecks_and_Cards_List.setAdapter(mSCA);
} else {
mSCA.swapCursor(mCursor);
}
}
/**
* Converts numeric cardvalue (1-13) and suit to a decriptive name
* @param cardvalue
* @param suit
* @return
*/
private String generateCardValueDescription(int cardvalue, int suit) {
String rv;
switch (cardvalue) {
case 1:
rv = "Ace of " + SUITS[suit];
break;
case 11:
rv = "Jack of " + SUITS[suit];
break;
case 12:
rv = "Queen of " + SUITS[suit];
break;
case 13:
rv = "King of " + SUITS[suit];
break;
default:
rv = String.valueOf(cardvalue) + " of " + SUITS[suit];
}
return rv;
}
}
Результирующее мини-приложение: -