Insert a list of objects in the local base, Room - android

I have the CidVo class:
#Entity
public class CidVo implements Serializable {
private static final long serialVersionUID = 6128323407787450445L;
#NonNull
#PrimaryKey
private String idCid;
private String dsCid;
//private StatusType idStatus;
public CidVo() {
super();
}
public String getIdCid() {
return idCid;
}
public void setIdCid(String idCid) {
this.idCid = idCid;
}
public String getDsCid() {
return dsCid;
}
public void setDsCid(String dsCid) {
this.dsCid = dsCid;
}
/*public StatusType getIdStatus() {
return idStatus;
}
public void setIdStatus(StatusType idStatus) {
this.idStatus = idStatus;
} */
}
The DAO class:
#Dao
public interface CIDDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAllCID(ArrayList<CidVo>... cidVos);
}
I get a list of objects, via JSON. And I would like to save it in the database.
But, I get this return error when trying to compile:
Error:Entity class must be annotated with #Entity
E:\workspace_android_studio\app_atendimento_branch_test\app\src\main\java\br\com\sisteplan\app\atendimento\Model\CIDDao.java
Error:(19, 43) error: Type of the parameter must be a class annotated
with #Entity or a collection/array of it.
How to solve this question?
The following is the postExecute:
#Override
protected void onPostExecute(AsyncTaskResult<Retorno> respAtestadoVo) {
super.onPostExecute(respAtestadoVo);
if (respAtestadoVo.getExceptionResult() == null) {
RetornoCid retornoCid = (RetornoCid) respAtestadoVo.getResult();
ArrayList<CidVo> cidVos = (ArrayList<CidVo>) retornoCid.getRetorno();
appDataBase.getCidDao().insertAllCID(cidVos);
Toast.makeText(context, "Sucesso", Toast.LENGTH_SHORT).show();
}
}
Instance:
#Database(entities = {CidVo.class}, version = 1)
public abstract class AppDataBase extends RoomDatabase {
public abstract CIDDao getCidDao();
private static AppDataBase appDataBase;
public static AppDataBase getInstance(Context context){
if(null == appDataBase){
appDataBase = buildDataBaseInstance(context);
}
return appDataBase;
}
private static AppDataBase buildDataBaseInstance(Context context){
return Room.databaseBuilder(context,
AppDataBase.class,
"app_database")
.allowMainThreadQueries().build();
}
private void cleanUp(){
appDataBase = null;
}
}

The reason is a vararg notation here void insertAllCID(ArrayList<CidVo>... cidVos);
You're trying to insert an array of array lists.
So, just replace it with
void insertAllCID(List<CidVo> cidVos);
Also, it's better to use interfaces over implementations, when you're working with collections. So, you can change this part
RetornoCid retornoCid = (RetornoCid) respAtestadoVo.getResult();
ArrayList<CidVo> cidVos = (ArrayList<CidVo>) retornoCid.getRetorno();
to this
RetornoCid retornoCid = (RetornoCid) respAtestadoVo.getResult();
List<CidVo> cidVos = new ArrayList(retornoCid.getRetorno());

Related

Get data after second query after inserting room data on android

I am using room persistence library for save some data and get these data.
Firstly I insert some data to room and after that I try to get inserted data in another fragment. But first time it is empty, after opening fragment second time it shows data. What I forget?
#Database(entities = {Cart.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract CartDao m=CartDao();
public static synchronized AppDatabase getInstance(Context ctx) {
if (INSTANCE == null)
INSTANCE = Room.databaseBuilder(ctx.getApplicationContext(),
AppDatabase.class, "db")
.fallbackToDestructiveMigration()
.enableMultiInstanceInvalidation()
.build();
return INSTANCE;
}
}
public class CartRepository {
private Application application;
private static CartRepository CartRepository;
private CartDao mCartDao;
private CartRepository(Application application) {
this.application = application;
AppDatabase db;
db = AppDatabase.getInstance(application);
mCartDao = db.mCartDao();
}
public synchronized static CartRepository getInstance(Application application) {
if (CartRepository == null) {
CartRepository = new CartRepository(application);
}
return CartRepository;
}
public void addCart(Cart cart) {
InsertAsyncTask task = new InsertAsyncTask(mCartDao);
task.execute(cart);
}
public List<Cart> getCartList() throws ExecutionException, InterruptedException {
return new GetAllCartAsyncTask(mCartDao).execute().get();
}
private static class InsertAsyncTask extends AsyncTask<Cart, Void, Void> {
private CartDao asyncTaskDao;
InsertAsyncTask(CartDao dao) {
asyncTaskDao = dao;
}
#Override
protected Void doInBackground(final Cart... result) {
asyncTaskDao.addCart(result[0]);
return null;
}
}
private static class GetAllCartAsyncTask extends AsyncTask<Void, Void, List<Cart>> {
private CartDao asyncTaskDao;
GetAllCartAsyncTask(CartDao dao) {
asyncTaskDao = dao;
}
#Override
protected List<Cart> doInBackground(Void... voids) {
return asyncTaskDao.getCartList();
}
}
}
FirstFragment
mCartRepository = CartRepository.getInstance(getActivity().getApplication());
mCartRepository .addCart(cart);
SecondFragment
mCartRepository = CartRepository.getInstance(getActivity().getApplication());
List<Cart> cartList = mCartRepository.getCartList();
// cartList.size is 0 after inserting, only after start fragment again it shows data
if (cartList.size() > 0) {
mList.addAll(cartList);
item_id = cartList.get(0).getItem_id();
}

Populate Room Database with Arraylist

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...
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;
}
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);
}
Furthermore created the DataBase Class:
#Database(entities = {SaveDeck.class}, version = 1)
public abstract class SaveDecksDataBase extends RoomDatabase {
public abstract DeckBuilderDao deckBuilderDao();
}
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();
}
}
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.
Android Room Database
Practice set

Room Library - Initializing Cursor Error?

I'm using room database in my application. Android emulator and %99 of my user's devices has no problem with it, but some of my users gets that error.
java.lang.IllegalStateException: Couldn't read row 0, col 1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
Full Error
android.database.CursorWindow.nativeGetString (CursorWindow.java)
android.database.AbstractWindowedCursor.getString (AbstractWindowedCursor.java:66)
me.ibrahimsn.applock.data.local.app.AppDao_Impl.getAllApps (AppDao_Impl.java:202)
me.ibrahimsn.applock.data.local.app.AppRepository.getAll (AppRepository.java:20)
me.ibrahimsn.applock.ui.start.StartViewModel.updateApps (StartViewModel.java:51)
me.ibrahimsn.applock.ui.start.StartActivity.onCreate (StartActivity.java:48)
I'm using it with Dagger 2 and here is my classes
#Database(entities = {App.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract AppDao appDao();
public static AppDatabase getAppDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "mydb")
.allowMainThreadQueries().build();
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
}
Dagger Module
#Module
public class ApplicationModule {
#Provides
#Singleton
AppDatabase provideRoomDatabase(Context context) {
return AppDatabase.getAppDatabase(context);
}
#Provides
#Singleton
AppDao provideAppDao(AppDatabase appDatabase) {
return appDatabase.appDao();
}
}
Dao
#Dao
public interface AppDao {
#Query("SELECT * FROM app")
List<App> getAllApps();
#Query("SELECT * FROM app WHERE label LIKE :query ORDER BY status DESC")
List<App> findApps(String query);
#Query("SELECT * FROM app WHERE status = 1")
List<App> getLockedApps();
#Insert
void insertAll(App... apps);
#Update
void update(App app);
#Query("UPDATE app SET status = :st")
void updateAll(Integer st);
#Delete
void delete(App app);
}
Repository
#Singleton
public class AppRepository {
private final AppDao appDao;
#Inject
public AppRepository(AppDao appDao) {
this.appDao = appDao;
}
public List<App> getAll() {
return appDao.getAllApps();
}
public List<App> find(String query) {
return appDao.findApps(query);
}
public void insert(App... apps) {
appDao.insertAll(apps);
}
public void update(App app) {
appDao.update(app);
}
public void updateAll(Boolean status) {
appDao.updateAll(status ? 1 : 0);
}
public void delete(App app) {
appDao.delete(app);
}
}
And here is the error file
public class StartViewModel extends ViewModel {
private final AppRepository repository;
private final PackageManager packageManager;
private final IconHelper iconHelper;
private final MutableLiveData<Boolean> status = new MutableLiveData<>();
#Inject
StartViewModel(AppRepository repository, PackageManager packageManager) {
this.repository = repository;
this.packageManager = packageManager;
this.iconHelper = new IconHelper(packageManager);
}
void updateApps() {
Intent launcherIntent = new Intent(Intent.ACTION_MAIN, null);
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> Resolves = this.packageManager.queryIntentActivities(launcherIntent, 0);
List<String> AppPackages = new ArrayList<>();
List<String> ResolvePackages = new ArrayList<>();
List<App> Apps = repository.getAll(); //Error is here
for(App a : Apps) AppPackages.add(a.getPackageName());

List<> from Room Database is always null

The following classes are used to store a list of surveys in a Room database. LiveData is used to be able to update
Entity class for Database:
#Entity
public class Survey {
#PrimaryKey
#NonNull
private String surveyID;
private String surveyName;
private String url;
private double lat;
private double lng;
private double radius;
public Survey(String surveyID, String surveyName, double lat, double lng, double radius, String url) {
this.surveyID = surveyID;
this.surveyName = surveyName;
this.lat = lat;
this.lng = lng;
this.radius = radius;
this.url = url;
}
Respective Dao Interface:
#Dao
public interface SurveyDao {
#Query("SELECT * FROM Survey")
LiveData<List<Survey>> getListOfSurveys();
/* Rest omitted */
}
Respective Repository class
public class SurveyRepository {
private final SurveyDao surveyDao;
#Inject
public SurveyRepository (SurveyDao surveyDao){
this.surveyDao = surveyDao;
}
public LiveData<List<Survey>> getListOfSurveys(){
return surveyDao.getListOfSurveys();
}
/* Rest omitted */
}
ViewModel:
public class SurveyCollectionViewModule extends ViewModel {
private SurveyRepository repository;
public SurveyCollectionViewModule(SurveyRepository repository) {
this.repository = repository;
}
public LiveData<List<Survey>> getSurveys(){
return repository.getListOfSurveys();
}
/* Rest Omitted */
}
Using all of this, I have setup a Fragment which has a RecyclerView displaying the list of surveys. The list is obtained in the following way:
public void onActivityCreated(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
surveyCollectionViewModule = ViewModelProviders.of(this, viewModelFactory)
.get(SurveyCollectionViewModule.class);
surveyCollectionViewModule.getSurveys().observe(this, new Observer<List<Survey>>() {
#Override
public void onChanged(#Nullable List<Survey> surveys) {
if(SurveyListFragment.this.listOfSurveys == null) {
setSurveyData(listOfSurveys);
}
}
});
}
However, I am running into the problem, where the call to getItemCount() in the adapter fails due to this list being NULL. The database does not contain any entries but I am still at a lost as to why the list is always returning as null.
Your onChanged doesn't actually use the surveys parameter it is given, change it to call setSurveyData(surveys) to actually fill out your data.
make some changes in ViewModel class like below ...
private final LiveData<List<Survey>> SurveyList;
private AppDatabase appDatabase;
public SurveyCollectionViewModule(Application application) {
appDatabase = AppDatabase.getDatabase(this.getApplication());
SurveyList = appDatabase.surveyDao().getAllSurvey();
}
public LiveData<List<Survey>> getSurveys() {
return SurveyList;
}

Using room persistence when trying to fetch items or insert returns null database

Working with room persistence, when trying to get the database to insert or make select in the items, the error appears:
AppDataBase.getMovieDao()' on a null object reference
The classes related to the process are as follows:
AppDataBase class:
#Database(entities = {Movies.class}, version = 1)
public abstract class AppDataBase extends RoomDatabase {
public static final String DB_NAME = "Movies";
private static AppDataBase INSTANCE;
public static AppDataBase getDataBase(Context context){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),AppDataBase.class,DB_NAME).build();
}
return INSTANCE;
}
public abstract MovieDao getMovieDao();
}
Dao Class:
#Dao
public interface MovieDao {
#Insert
void insertAll(Movies movies);
#Update
void updateAll(Movies... notes);
#Query("SELECT * FROM moviestb")
List<Movies> getAll();
#Delete
void deleteAll(Movies... notes);
}
Entity class:
#Entity(tableName = "moviestb")
public class Movies {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "idmovie")
private long id;
#ColumnInfo(name = "titlemovie")
private String titlemovie;
........
}
Searching for the registrations:
public void loadFromDB(){
db.getDataBase(view.getContext());
if(db.getMovieDao().getAll().size() > 0){
adapter.setResults(db.getMovieDao().getAll());
}else{
Toast.makeText(view.getContext(),"Não há filmes cadastrados",Toast.LENGTH_SHORT).show();
view.getActivity().finish();
}
}
Insert:
public View.OnClickListener onSaveClick(final String plot, final String diretor, final String autor,
final String nome, final String tipo, final String ano, final String ator, final String imdb) {
return new View.OnClickListener() {
#Override
public void onClick(View itemView) {
db.getDataBase(view.getContext());
Movies movies = new Movies(nome,plot,imdb,"",ator,ano,tipo,diretor,autor);
new InsertAsyncTask(db).execute(movies);
}
};
}
private class InsertAsyncTask extends AsyncTask<Movies,Void,Void>{
private AppDataBase db;
public InsertAsyncTask(AppDataBase appDataBase) {
db = appDataBase;
}
#Override
protected Void doInBackground(Movies... params) {
db.getMovieDao().insertAll(params[0]);
return null;
}
}
Searching all:
public void loadFromDB(){
db.getDataBase(view.getContext());
if(db.getMovieDao().getAll().size() > 0){
adapter.setResults(db.getMovieDao().getAll());
}else{
Toast.makeText(view.getContext(),"Não há filmes cadastrados",Toast.LENGTH_SHORT).show();
view.getActivity().finish();
}
}
The crash occurs while fetching the database, what am I doing wrong? thank you!
db is null, apparently. Your question does not show where you ever assign it a value.
Please note that getDataBase() is a static method. Perhaps you should have a db=AppDataBase.getDataBase() statement somewhere.

Categories

Resources