1
votes

I would like to build a Deckbuilder that allows you to save created decks locally on the device.

The Decklist are stored in Arraylists, called TransferDeck. Which I would like to store in room database. My issue is, that I do not know how to populate my database correctly, with the data comming out of the Arraylist.

I am used to working with Arraylist and below you see my try for storing the data:

So this is what I tried but what sadly does not work:

private void populateDB(final List<TransferDeck> mTransferDeck) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    List<SaveDeck> mSaveDeck = new ArrayList<>();
                    for(int i = 0; i<mTransferDeck.size(); i++){
                        mSaveDeck.add(new SaveDeck(i, "FirstSavedDeck", mTransferDeck.get(i).getCardImage() ,mTransferDeck.get(i).getTypeImage(), mTransferDeck.get(i).getCost(), mTransferDeck.get(i).getName(), mTransferDeck.get(i).getNumber()));
                    }
                    mSavedDecksDB.deckBuilderDao().insertCards(mSaveDeck);

                }
            }).start();
}

Below you can find the rest of my code, but the above one should be enough to make clear what I want to do...

  1. I created the class SaveDeck which should be able to Save a Deck with a given Deckname: :-

    @Entity public class SaveDeck implements Serializable { @PrimaryKey(autoGenerate = true) private int _id;

    public SaveDeck(int _id, String deckName, int cardImage, int typeImage, Integer cardCost, String cardName, Integer cardNumber) {
        this._id = _id;
        DeckName = deckName;
        CardImage = cardImage;
        TypeImage = typeImage;
        CardCost = cardCost;
        CardName = cardName;
        CardNumber = cardNumber;
    }
    
    @ColumnInfo(name = "DeckName")
    private String DeckName;
    
    @ColumnInfo(name = "CardImage")
    private int CardImage;
    
    @ColumnInfo(name = "TypeImage")
    private int TypeImage;
    
    @ColumnInfo(name = "CardCost")
    private Integer CardCost;
    
    @ColumnInfo(name = "CardName")
    private String CardName;
    
    @ColumnInfo(name = "CardNumber")
    private Integer CardNumber;
    

    }

  2. I created the Dao Class as follows: :-

    @Dao public interface DeckBuilderDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public long[] insertCards(SaveDeck... saveDecks);
    
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    public long insertCard(SaveDeck saveDecks);
    
    @Update
    public int updateCardBaseEntries(SaveDeck... saveDecks);
    
    @Update
    public int updateCardBaseEntry(SaveDeck saveDecks);
    
    @Delete
    public int deleteCardBaseEntried(SaveDeck... saveDecks);
    
    @Delete
    public int deleteCardBaseEntry(SaveDeck saveDecks);
    
    @Query("SELECT * FROM SaveDeck")
    public SaveDeck[] getAllDecks();
    
    //probably I do not need the getAllDecks Query. Right now I only need the following one:
    @Query("SELECT * FROM SaveDeck WHERE DeckName = :NameOfDeck ORDER  BY DeckName, CardName")
    public SaveDeck getOneDeck(String NameOfDeck);
    

    }

  3. Furthermore created the DataBase Class:

    @Database(entities = {SaveDeck.class}, version = 1)
    public abstract class SaveDecksDataBase extends RoomDatabase {
        public abstract DeckBuilderDao deckBuilderDao();
    }
    
  4. The last class is a fragment, where I try to populate my database, and in the populateDB() class is the issue

    public class review_fragment extends Fragment {

    private List<TransferDeck> mTransferDeck = DataHolder.getInstance().savedDecklistTransfer;
    SaveDecksDataBase mSavedDecksDB;
    Cursor mCursor;
    
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    //return super.onCreateView(inflater, container, savedInstanceState);
        View view = inflater.inflate(R.layout.review_fragment, container, false);
    
        /*Introduce Cards Recycler*/
    
        RecyclerView rvCards = view.findViewById(R.id.rv_review_cardlist);
        rvCards.setLayoutManager(new GridLayoutManager(getActivity(), 5));
        review_RViewAdapter_Cards adapterCards = new review_RViewAdapter_Cards(getContext(), mTransferDeck);
        rvCards.setAdapter(adapterCards);
    
    
    
        /*Init Room database*/
        mSavedDecksDB = Room.databaseBuilder(getActivity(),SaveDecksDataBase.class,"SavedDecksDB.db").build();
        populateDB(mTransferDeck);
    
        return view;
    }
    
    private void populateDB(final List<TransferDeck> mTransferDeck) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                List<SaveDeck> mSaveDeck = new ArrayList<>();
                for(int i = 0; i<mTransferDeck.size(); i++){
                    mSaveDeck.add(new SaveDeck(i, "FirstSavedDeck", mTransferDeck.get(i).getCardImage() ,mTransferDeck.get(i).getTypeImage(), mTransferDeck.get(i).getCost(), mTransferDeck.get(i).getName(), mTransferDeck.get(i).getNumber()));
                }
                mSavedDecksDB.deckBuilderDao().insertCards(mSaveDeck);
    
            }
        }).start();
    }
    

    }

1

1 Answers

1
votes

I like to mention that this should be a comment rather than an answer.

First, either use AysncTask or use more robust Executors.newSingleThreadExecutor(). If you prefer the second one then it's best if you create a helper class (example). Example:

private void populateDB(final List<TransferDeck> mTransferDeck) {
    AppExecutors.diskIO().execute(() -> {

        for(int i = 0; i<mTransferDeck.size(); i++){
            mSavedDecksDB.deckBuilderDao().insertCards(new SaveDeck(...);
        }

    });
}

(1) Create a blank constructor.

(4) Room Database should not be initialized there and it's best if it's singleton. So the your database class (3) can be like:

public abstract class SaveDecksDataBase extends RoomDatabase {

   private static SaveDecksDataBase sINSTANCE;
   private static final Object LOCK = new Object();

   public static SaveDecksDataBase getDatabase(final Context context) {
        if (sINSTANCE == null) {
            synchronized (LOCK) {
                if (sINSTANCE == null) {
                    sINSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            SaveDecksDataBase.class, "SavedDecksDB.db")
                            .build();
                }
            }
        }
        return sINSTANCE;
    }

    public abstract DeckBuilderDao deckBuilderDao();
}

Lastly, to get SaveDeck object you also has to use Executors or AsyncTask to do the work in background, and then populate the RecyclerView.

  1. Android Room Database
  2. Practice set