Android Room - Get the id of new inserted row form #Insert - android

In my code below I'm getting rowId. I've read that it's also possible to get the last inserted row id from #Insert directly. In my code I changed void insert to long and tried many other things as in examples I found on the internet, but every time I get errors. Would you like to provide me a code/solution to get the row/user ID from #Insert?
#Dao
public interface UserDao {
#Insert
void insert(UserEntity userEntity);
#Update
void update(UserEntity userEntity);
#Delete
void delete(UserEntity userEntity);
#Query("DELETE FROM user_table")
void deleteAllUsers();
#Query("SELECT * FROM user_table")
LiveData<List<UserEntity>> getAllUsers();
// ====== from here ======
#Query("SELECT * FROM user_table")
LiveData<UserEntity> getRowId();
// ====== till here ======
}
Entity
#Entity(tableName = "user_table")
public class UserEntity {
#PrimaryKey(autoGenerate = true)
private int id;
private String userName;
private String userTelephoneNumber;
public UserEntity(String userName, String userTelephoneNumber) {
this.userName = userName;
this.userTelephoneNumber = userTelephoneNumber;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public String getUserName() {
return userName;
}
public String getUserTelephoneNumber() {
return userTelephoneNumber;
}
}
Repository
public class UserRepository {
private UserDao userDao;
private LiveData<List<UserEntity>> allUsers;
public UserRepository(Application application) {
HandymanDatabase handymanDatabase = HandymanDatabase.getInstance(application);
userDao = handymanDatabase.userDao();
allUsers = userDao.getAllUsers();
}
public void insert(UserEntity userEntity) {
new InsertUserAsyncTask(userDao).execute(userEntity);
}
public void update(UserEntity userEntity) {
new UpdateUserAsyncTask(userDao).execute(userEntity);
}
public void delete(UserEntity userEntity) {
new DeleteUserAsyncTask(userDao).execute(userEntity);
}
public void deleteAllUsers() {
new DeleteAllUsersAsyncTask(userDao).execute();
}
public LiveData<List<UserEntity>> getAllUsers() {
return allUsers;
}
// ====== from here ======
public LiveData<UserEntity> getRowId() {
return userDao.getRowId();
}
// ====== till here ======
private static class InsertUserAsyncTask extends AsyncTask<UserEntity, Void, Void> {
private UserDao userDao;
private InsertUserAsyncTask(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected Void doInBackground(UserEntity... userEntities) {
userDao.insert(userEntities[0]);
return null;
}
}
private static class UpdateUserAsyncTask extends AsyncTask<UserEntity, Void, Void> {
private UserDao userDao;
private UpdateUserAsyncTask(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected Void doInBackground(UserEntity... userEntities) {
userDao.update(userEntities[0]);
return null;
}
}
private static class DeleteUserAsyncTask extends AsyncTask<UserEntity, Void, Void> {
private UserDao userDao;
private DeleteUserAsyncTask(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected Void doInBackground(UserEntity... userEntities) {
userDao.delete(userEntities[0]);
return null;
}
}
private static class DeleteAllUsersAsyncTask extends AsyncTask<Void, Void, Void> {
private UserDao userDao;
private DeleteAllUsersAsyncTask(UserDao userDao) {
this.userDao = userDao;
}
#Override
protected Void doInBackground(Void... voids) {
userDao.deleteAllUsers();
return null;
}
}
}
ViewModel
public UserViewModel(#NonNull Application application) {
super(application);
userRepository = new UserRepository(application);
allUsers = userRepository.getAllUsers();
}
public void insert(UserEntity userEntity) {
userRepository.insert(userEntity);
}
public void update(UserEntity userEntity) {
userRepository.update(userEntity);
}
public void delete(UserEntity userEntity) {
userRepository.delete(userEntity);
}
public void deleteAllUsers() {
userRepository.deleteAllUsers();
}
public LiveData<List<UserEntity>> getAllUsers() {
return allUsers;
}
// ====== from here ======
public LiveData<UserEntity> getRowId() {
return userRepository.getRowId();
}
// ====== till here ======
}
Fragment/Activity
public class UserFavoritesFragment extends Fragment {
private static final String TAG = "UserFavoritesFragment";
private UserViewModel userViewModel;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = getLayoutInflater().inflate(R.layout.fragment_user_favorites, container, false);
final TextView textViewUserName = view.findViewById(R.id.textViewUserName);
TextView textViewUserPhone = view.findViewById(R.id.textViewUserPhone);
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
// ====== from here ======
userViewModel.getRowId().observe(getViewLifecycleOwner(), new Observer<UserEntity>() {
#Override
public void onChanged(UserEntity userEntity) {
long rowId = userEntity.getId();
Log.d(TAG, "onChanged: " + rowId);
}
});
// ====== till here ======
return view;
}
}

You can do that using a listener interface that has a callback that accepts a long value of the inserted row id in the database.
Listener Interface
public interface NewIdListener {
void onInsert(long id);
}
Dao
#Dao
public interface UserDao {
#Insert
long insert(UserEntity userEntity); // return id of the inserted userEntity
}
Repository
public class UserRepository {
private Executor mExecutor = Executors.newSingleThreadExecutor();
private UserDao userDao;
...
public void insertUserEntity(final UserEntity entity, final NewIdListener listener) {
mExecutor.execute(new Runnable() {
#Override
public void run() {
listener.onInsert(userDao.insert(entity));
}
});
}
ViewModel
public void insertUserEntity(UserEntity entity, NewIdListener listener) {
userRepository.insertUserEntity(entity, listener);
}
Activity
userViewModel.insertUserEntity(new UserEntity("User Name", "12345678"), new NewIdListener() {
#Override
public void onInsert(final long id) {
requireActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(requireActivity(), "Id: " + id, Toast.LENGTH_SHORT).show();
}
});
}
});
Note: For background thread, I've used Executor instead of AsyncTask as AsyncTask is deprecated now.

Related

Room database elements are not showing up

Database inspector shows the database is working but not able to show it up in RecyclerView.
product.java
#Entity (tableName = "productTable")
public class product {
#PrimaryKey(autoGenerate = true)
private int pid;
#ColumnInfo(name = "product_name")
private String productName;
#ColumnInfo(name = "price")
private String price;
#ColumnInfo(name = "category")
private String category;
#ColumnInfo(name = "company")
private String companyName;
public product(String productName, String price, String category, String companyName) {
this.productName = productName;
this.price = price;
this.category = category;
this.companyName = companyName;
}
public int getPid() {
return pid;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public void setPid(int pid) {
this.pid = pid;
}
}
productDao.java
#Dao
public interface productDAO {
#Query("SELECT * FROM productTable")
LiveData<List<product>> getAllprod();
// #Query("SELECT * FROM product WHERE product_name order by product_name")
// product findByName(String product, String price);
#Query("SELECT * FROM productTable where :company order by product_name")
product section(String company);
#Query("DELETE FROM productTable WHERE pid = :id")
int deleteProduct(int id);
#Insert
void insert(product product);
#Update
void update(product product);
#Delete
void delete(product product);
#Query("DELETE FROM productTable")
void deleteAll();
}
productDatabase.java
#Database(entities = {product.class},version = 1)
public abstract class productDatabase extends RoomDatabase {
public static volatile productDatabase INSTANCE;
public abstract productDAO proDao();
public static productDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
synchronized (productDatabase.class) {
if (INSTANCE == null) {
//create our db
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
productDatabase.class, "product_database")
.fallbackToDestructiveMigration()
.build();
}
}
}
return INSTANCE;
}
}
productRepository.java
public class productRepository {
private productDAO proDao;
private LiveData<List<product>> productList;
public productRepository(Application application)
{
productDatabase db = productDatabase.getDatabase(application);
proDao = db.proDao();
productList = proDao.getAllprod();
}
public LiveData<List<product>> getAllrepo(){
return productList;
}
public void insert(product prod){
new insertAsyncTask(proDao).execute(prod);
}
public void delete(product prod){
new deleteAsyncTask(proDao).execute(prod);
}
public void update(product prod){
new updateAsyncTask(proDao).execute(prod);
}
private class insertAsyncTask extends AsyncTask<product,Void,Void>{
private productDAO asyncTaskDao;
public insertAsyncTask(productDAO dao){
asyncTaskDao = dao;
}
#Override
protected Void doInBackground(product... products) {
asyncTaskDao.insert(products[0]);
return null;
}
}
private class deleteAsyncTask extends AsyncTask<product,Void,Void>{
private productDAO asyncTaskDao;
public deleteAsyncTask(productDAO proDao) {
asyncTaskDao = proDao;
}
#Override
protected Void doInBackground(product... products) {
asyncTaskDao.delete(products[0]);
return null;
}
}
private class updateAsyncTask extends AsyncTask<product,Void,Void>{
private productDAO asyncTaskDao;
public updateAsyncTask(productDAO proDao) {
asyncTaskDao = proDao;
}
#Override
protected Void doInBackground(product... products) {
asyncTaskDao.delete(products[0]);
return null;
}
}
}
productViewModel.java+
public class productViewModel extends AndroidViewModel {
private productRepository proRepo;
private LiveData<List<product>> proList;
public productViewModel(#NonNull Application application) {
super(application);
proRepo = new productRepository(application);
proList = proRepo.getAllrepo();
}
public LiveData<List<product>> getProList(){
return proList;}
public void insert(product prod){
proRepo.insert(prod);}
public void update(product prod){
proRepo.update(prod);
}
public void delete(product prod){
proRepo.delete(prod);
}
}
MainActivity.Java
public class MainActivity extends AppCompatActivity {
private productAdapter productAdapter;
private productViewModel viewModel;
private TextView nothing;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nothing = findViewById(R.id.nothing);
viewModel = ViewModelProviders.of(this)
.get(productViewModel.class);
recyclerView = findViewById(R.id.productView);
productAdapter = new productAdapter(this);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
FloatingActionButton fab = findViewById(R.id.add_component);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, Add_Product.class));
}
});
viewModel.getProList().observe(this, new Observer<List<product>>() {
#Override
public void onChanged(#Nullable List<product> productLists) {
productAdapter.setList(productLists);
Log.d("hello", "process" + productLists);
}
});
if (productAdapter.getItemCount()!=0)
{
nothing.setVisibility(View.GONE);
Toast.makeText(this, "something not working",Toast.LENGTH_SHORT).show();
}
else
nothing.setVisibility(View.VISIBLE);
}
}
database inspector shows that database is made and also the saving process is also working but not able top display it in recyclerView
You forgot to attach the adapter to the RecyclerView
So, in your MainActivity activity do this in below
viewModel.getProList().observe(this, new Observer<List<product>>() {
#Override
public void onChanged(#Nullable List<product> productLists) {
productAdapter.setList(productLists);
recyclerView.setAdapter(productAdapter); // <<<<<< change here
Log.d("hello", "process" + productLists);
}
});

Room only prints the first line

I am writing a simple application that stores 2 string values in a database using Room (I am trying to learn this library). So, I have only one line on my list. Presented for the first time. The rest are not displayed. What is the reason for this behavior?
Model
#Entity
public class Note {
#PrimaryKey(autoGenerate = true)
private long id;
private String title;
private String text;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
NoteDao
#Dao
public interface NoteDao {
#Insert
void insert(Note note);
#Delete
void delete(Note note);
#Query("SELECT * FROM Note")
List<Note> getAllNotes();
}
AppDatabase
#Database(entities = Note.class, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract NoteDao getNoteDao();
}
DataManager
public class DataManager {
private AppDatabase appDatabase;
public DataManager (AppDatabase appDatabase) {
this.appDatabase = appDatabase;
}
public List <Note> getNotes () {
try {
return new GetNotes (). execute (). get ();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace ();
return null;
}
}
public void insertNote (Note note) {
new InsertNote (note) .execute ();
}
public void deleteNote (Note note) {
new DeleteNote (note) .execute ();
}
// Get all notes
public class GetNotes extends AsyncTask <Void, Void, List <Note>> {
#Override
protected List <Note> doInBackground (Void ... voids) {
return appDatabase.getNoteDao (). getAllNotes ();
}
}
// Insert note
public class InsertNote extends AsyncTask <Void, Void, Void> {
private Note note;
InsertNote (Note note) {
this.note = note;
}
#Override
protected Void doInBackground (Void ... voids) {
appDatabase.getNoteDao (). insert (note);
return null;
}
}
// Delete note
public class DeleteNote extends AsyncTask <Void, Void, Void> {
private Note note;
public DeleteNote (Note note) {
this.note = note;
}
#Override
protected Void doInBackground (Void ... voids) {
appDatabase.getNoteDao (). delete (note);
return null;
}
}
}
Mvp
public interface NoteListView extends MvpView {
void showNoteList(List<Note> note);
}
Presenter
public class NoteListPresenter extends MvpPresenter<NoteListView> {
private DataManager dataManager;
public NoteListPresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
public void getNotes(){
getView().showNoteList(dataManager.getNotes());
}
public void deleteNote(Note note) {
dataManager.deleteNote(note);
getView().showNoteList(dataManager.getNotes());
}
}
Adapter
public class NoteAdapter extends RecyclerView.Adapter<NoteAdapter.ViewHolder> {
private List<Note> listNote;
private Context context;
public NoteAdapter(Context context, List<Note> listNote) {
this.listNote = listNote;
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.title.setText(listNote.get(position).getTitle());
holder.text.setText(listNote.get(position).getText());
}
#Override
public int getItemCount() {
return listNote.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView title, text;
public ViewHolder(#NonNull View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
text = itemView.findViewById(R.id.text);
}
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements NoteListView {
private NoteListPresenter presenter;
private RecyclerView recyclerView;
private NoteAdapter noteAdapter;
private ConstraintLayout constraintLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.coordinatorMain);
recyclerView = findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
presenter = new NoteListPresenter(App.getDataManager());
presenter.attachView(this);
presenter.getNotes();
}
public void onNextActivity(View view){
startActivity(new Intent(MainActivity.this, AddNoteActivity.class));
}
#Override
public void showNoteList(List<Note> note) {
noteAdapter = new NoteAdapter(this, note);
recyclerView.setAdapter(noteAdapter);
}
#Override
protected void onResume() {
super.onResume();
presenter.getNotes();
}
#Override
public void showMessage(String message) {
Snackbar.make(constraintLayout, message, Snackbar.LENGTH_SHORT).show();
}
}
UPD
SaveNoteView
public interface SaveNoteView extends MvpView {
void insertNote(Note note);
}
SaveNotePresenter
public class SaveNotePresenter extends MvpPresenter<SaveNoteView> {
private DataManager dataManager;
public SaveNotePresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
public void insertNote(Note note){
dataManager.insertNote(note);
getView().insertNote(note);
}
}
AddNoteActivity
public class AddNoteActivity extends AppCompatActivity implements SaveNoteView {
private TextInputEditText title, text;
private ConstraintLayout constraintLayout;
private SaveNotePresenter presenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_note);
constraintLayout = findViewById(R.id.constrainAdd);
title = findViewById(R.id.titleEditText);
text = findViewById(R.id.textEditText);
presenter = new SaveNotePresenter(App.getDataManager());
presenter.attachView(this);
}
//Save a note
public void saveNote(View view){
Note note = new Note();
note.setTitle(title.getText().toString());
note.setText(text.getText().toString());
presenter.insertNote(note);
finish();
}
#Override
public void insertNote(Note note) {
DataManager dataManager = App.getDataManager();
dataManager.insertNote(note);
}
#Override
public void showMessage(String message) {
Snackbar.make(constraintLayout, message, Snackbar.LENGTH_SHORT).show();
}
}
It's pretty likely that there is only 1 id which is beeing replaced the whole time (if this is not the case, check how often insertion is done)
I used Kotlin with Room but in this official example they have a public autogenerated primaryKey, which might be required for Room to access it and autogenerate it. So make the variable public and see if it works
There was no problem. I just specified the parent layout for item_list in full screen. Therefore, the subsequent ones were not visible. Silly mistake:D

Problem with Live Data observers in Room DB Android

I have problem with observing 3 different lists with live data observer for viewing them in one single recycler view.
This is the scenario: In ListsFragment, I have TabLayout with 3 tabs (WANT, PLAYING, PLAYED) and 1 recycler view. On different tab click I load different lists of games from database and I am presenting them with Live Data observer pattern in the recycler view. Until this moment everything works OK.
The problem occurs when I press one game DELETE button, the database is updated but in the recycler view is loading wrong list and not the list of the selected tab (Probably because there are 3 active observers), so the data on the screen is updated with wrong games.
Gif of the behaviour:
https://gfycat.com/showyembarrassedbarasingha
Can anyone please help me, I tried many solutions but nothing helped and I am stuck more than 1 month.
This is the code.
Fragment:
public class ListsFragment extends Fragment implements VisitedGameInterface {
public static final String TAG = ListsFragment.class.getSimpleName();
private static final int WANT = 0;
private static final int PLAYING = 1;
private static final int PLAYED = 2;
private int selectedTab = WANT;
private GameViewModel gameViewModel;
private GameVisitedAdapter gameAdapter;
private TextView noGamesTV;
public ListsFragment() {
// Required empty public constructor
}
public static ListsFragment newInstance(Bundle bundle) {
ListsFragment fragment = new ListsFragment();
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_lists, container, false);
TabLayout listsTabLayout = view.findViewById(R.id.lists_tab_layout);
RecyclerView listsRecyclerView = view.findViewById(R.id.lists_recycler_view);
noGamesTV = view.findViewById(R.id.no_games_tv);
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.want)), true);
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.playing)));
listsTabLayout.addTab(listsTabLayout.newTab().setText(getString(R.string.played)));
listsTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
listsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), RecyclerView.VERTICAL, false));
listsRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
gameAdapter = new GameVisitedAdapter(getActivity(), this);
listsRecyclerView.setAdapter(gameAdapter);
gameViewModel = ViewModelProviders.of(this).get(GameViewModel.class);
gameViewModel.getWantedGames().observe(this, new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> wantedGames) {
if (wantedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
}else {
noGamesTV.setText(R.string.no_wanted_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(wantedGames);
gameAdapter.notifyDataSetChanged();
}
});
listsTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (getActivity() != null && tab.getText() != null) {
if (tab.getText().equals("WANT")) {
selectedTab = tab.getPosition();
gameViewModel.getWantedGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> wantedGames) {
if (wantedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_wanted_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(wantedGames);
gameAdapter.notifyDataSetChanged();
}
});
} else if (tab.getText().equals("PLAYING")) {
selectedTab = tab.getPosition();
gameViewModel.getPlayingGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> playingGames) {
if (playingGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_playing_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(playingGames);
gameAdapter.notifyDataSetChanged();
}
});
} else if (tab.getText().equals("PLAYED")){
selectedTab = tab.getPosition();
gameViewModel.getPlayedGames().observe(getActivity(), new Observer<List<Game>>() {
#Override
public void onChanged(List<Game> playedGames) {
if (playedGames.size() != 0) {
noGamesTV.setVisibility(View.GONE);
} else {
noGamesTV.setText(R.string.no_played_games);
noGamesTV.setVisibility(View.VISIBLE);
}
gameAdapter.setGames(playedGames);
gameAdapter.notifyDataSetChanged();
}
});
}
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
return view;
}
#Override
public void onGameDelete(final Game game) {
if (selectedTab == WANT){
game.setWanted(false);
showSnackBar(game, WANT);
} if (selectedTab == PLAYING){
game.setPlaying(false);
showSnackBar(game, PLAYING);
} if (selectedTab == PLAYED){
game.setPlayed(false);
showSnackBar(game, PLAYED);
}
gameViewModel.update(game);
gameAdapter.notifyDataSetChanged();
}
#Override
public void onVisitedGameClick(Game game) {
Intent intent = new Intent(getActivity(), GameActivity.class);
intent.putExtra("game", game);
startActivity(intent);
}
private void showSnackBar(final Game snackGame, final int selectedTab){
Snackbar snackbar = Snackbar.make(Objects.requireNonNull(getView()), snackGame.getName() + " deleted", Snackbar.LENGTH_LONG)
.setAction(R.string.undo, new View.OnClickListener() {
#Override
public void onClick(View view) {
if (selectedTab == WANT) snackGame.setWanted(true);
if (selectedTab == PLAYING) snackGame.setPlaying(true);
if (selectedTab == PLAYED) snackGame.setPlayed(true);
gameViewModel.insert(snackGame);
}
});
snackbar.show();
}
}
XML of ListsFragment
<RelativeLayout
android:id="#+id/lists_layout" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
tools:context=".fragment.ListsFragment">
<com.google.android.material.tabs.TabLayout
android:id="#+id/lists_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabSelectedTextColor="#color/button_blue"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/lists_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/lists_tab_layout"/>
<TextView
android:id="#+id/no_games_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
tools:text="No games at this moment"
android:textColor="#color/text_black"
android:visibility="invisible"/>
</RelativeLayout>
The adapter:
public class GameVisitedAdapter extends RecyclerView.Adapter<GameVisitedAdapter.GameVisitedViewHolder> {
private Context context;
private LayoutInflater inflater;
private List<Game> games = new ArrayList<>();
private VisitedGameInterface visitedGameInterface;
public GameVisitedAdapter(Context context, VisitedGameInterface visitedGameInterface){
this.context = context;
inflater = LayoutInflater.from(context);
this.visitedGameInterface = visitedGameInterface;
}
public void setGames(List<Game> games){
this.games = games;
}
#NonNull
#Override
public GameVisitedViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.item_game_visited, parent, false);
return new GameVisitedViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull GameVisitedViewHolder holder, int position) {
Game game = games.get(position);
if (game.getCover() != null) {
Glide
.with(context)
.load(context.getString(R.string.cover_url) + game.getCover().getImage_id() + ".jpg")
.centerCrop()
.placeholder(context.getResources().getDrawable(R.drawable.placeholder))
.into(holder.gameCover);
}
holder.gameTitle.setText(game.getName());
SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy");
String dateString = formatter.format((new Date((long) game.getFirst_release_date() * 1000)));
holder.gameYear.setText(dateString);
}
#Override
public int getItemCount() {
return games.size();
}
class GameVisitedViewHolder extends RecyclerView.ViewHolder {
private ImageView gameCover, gameDeleteButton;
private TextView gameTitle, gameYear;
GameVisitedViewHolder(#NonNull View itemView) {
super(itemView);
gameCover = itemView.findViewById(R.id.game_cover);
gameTitle = itemView.findViewById(R.id.game_name);
gameYear = itemView.findViewById(R.id.game_release_year);
gameDeleteButton = itemView.findViewById(R.id.game_delete_button);
gameDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
visitedGameInterface.onGameDelete(games.get(getAdapterPosition()));
}
});
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
visitedGameInterface.onVisitedGameClick(games.get(getAdapterPosition()));
}
});
}
}
}
The ViewModel
public class GameViewModel extends AndroidViewModel {
private GameRepository gameRepository;
public GameViewModel(#NonNull Application application) {
super(application);
gameRepository = new GameRepository(application);
}
public void insert(Game game){
gameRepository.insert(game);
}
public void update(Game game){
gameRepository.update(game);
}
public void deleteGame(Game game){
gameRepository.delete(game);
}
public void deleteAll(){
gameRepository.deleteAll();
}
public void DeleteVisitedGames(){ gameRepository.deleteVisitedGames();}
public LiveData<List<Game>> getWantedGames(){
return gameRepository.getWantedGames();
}
public LiveData<List<Game>> getPlayingGames(){
return gameRepository.getPlayingGames();
}
public LiveData<List<Game>> getPlayedGames(){
return gameRepository.getPlayedGames();
}
public LiveData<List<Game>> getVisitedGames(){
return gameRepository.getVisitedGames();
}
public LiveData<List<Game>> getAllGamesFromDB(){
return gameRepository.getAllGamesFromDB();
}
}
The Repository:
public class GameRepository {
private GameDao gameDao;
private LiveData<List<Game>> wantedGames;
private LiveData<List<Game>> playingGames;
private LiveData<List<Game>> playedGames;
private LiveData<List<Game>> visitedGames;
private LiveData<List<Game>> allGamesFromDB;
public GameRepository(Application application){
GameDatabase gameDatabase = GameDatabase.getInstance(application);
gameDao = gameDatabase.gameDao();
wantedGames = gameDao.getWantedGames();
playingGames = gameDao.getPlayingGames();
playedGames = gameDao.getPlayedGames();
visitedGames = gameDao.getVisitedGames();
allGamesFromDB = gameDao.getAllGamesFromDB();
}
public LiveData<List<Game>> getWantedGames(){
return wantedGames;
}
public LiveData<List<Game>> getPlayingGames(){
return playingGames;
}
public LiveData<List<Game>> getPlayedGames(){
return playedGames;
}
public LiveData<List<Game>> getVisitedGames(){
return visitedGames;
}
public LiveData<List<Game>> getAllGamesFromDB(){
return allGamesFromDB;
}
public void insert(Game game){
new InsertAsyncTask(gameDao).execute(game);
}
public void update(Game game){
new UpdateAsyncTask(gameDao).execute(game);
}
public void delete(Game game){
new DeleteItemAsyncTask(gameDao).execute(game);
}
public void deleteAll(){
new DeleteAllAsyncTask(gameDao).execute();
}
public void deleteVisitedGames() {new DeleteVisitedAsyncTask(gameDao).execute();}
//-------------INSERT GAME ASYNC TASK
private static class InsertAsyncTask extends AsyncTask<Game, Void, Void> {
private GameDao asyncDao;
public InsertAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.insert(games[0]);
return null;
}
}
//-------------UPDATE GAME ASYNC TASK
private static class UpdateAsyncTask extends AsyncTask<Game, Void, Void> {
private GameDao asyncDao;
public UpdateAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.updateGame(games[0]);
return null;
}
}
//----------DELETE GAME ASYNC TASK
private static class DeleteItemAsyncTask extends AsyncTask <Game, Void, Void> {
private GameDao asyncDao;
public DeleteItemAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Game... games) {
asyncDao.deleteGame(games[0]);
return null;
}
}
//-------------DELETE ALL ASYNC TASK
private static class DeleteAllAsyncTask extends AsyncTask <Void, Void, Void>{
private GameDao asyncDao;
public DeleteAllAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Void... voids) {
asyncDao.deleteAllGames();
return null;
}
}
//-------------DELETE VISITED GAMES ASYNC TASK
private static class DeleteVisitedAsyncTask extends AsyncTask <Void, Void, Void>{
private GameDao asyncDao;
public DeleteVisitedAsyncTask(GameDao asyncDao){
this.asyncDao = asyncDao;
}
#Override
protected Void doInBackground(Void... voids) {
asyncDao.deleteVisitedGames();
return null;
}
}
}
The DAO:
#Dao
public interface GameDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(Game game);
#Delete
void deleteGame(Game game);
#Update
void updateGame(Game game);
#Query("DELETE FROM game_table")
void deleteAllGames();
#Query("SELECT * FROM game_table WHERE isWanted")
LiveData<List<Game>> getWantedGames();
#Query("SELECT * FROM game_table WHERE isPlaying")
LiveData<List<Game>> getPlayingGames();
#Query("SELECT * FROM game_table WHERE isPlayed")
LiveData<List<Game>> getPlayedGames();
#Query("SELECT * FROM game_table WHERE isVisited")
LiveData<List<Game>> getVisitedGames();
#Query("SELECT * FROM game_table")
LiveData<List<Game>> getAllGamesFromDB();
#Query("DELETE FROM game_table WHERE isVisited")
void deleteVisitedGames();
}
Database:
#Database(entities = Game.class, version = 8, exportSchema = false)
#TypeConverters({Converters.class})
public abstract class GameDatabase extends RoomDatabase {
public abstract GameDao gameDao();
private static GameDatabase INSTANCE;
public static GameDatabase getInstance(Context context){
if (INSTANCE == null){
synchronized (GameDatabase.class){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
GameDatabase.class, "game_database")
.fallbackToDestructiveMigration()
.addCallback(sRoomDatabaseCallback)
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback(){
#Override
public void onOpen(#NonNull SupportSQLiteDatabase db) {
super.onOpen(db);
}
};
}
My 2cents: even after you change tabs, your observers are still active, as you are using the same table for everything and I believe (just glance at the code) you are updating your game entry (e.g: isPlayed set to false) thus it send updates to all active observers thus sending update to the recylerview.
With that in mind, in case I am right here, you can:
Make 3 distinct tables (can be in the same database)
use viewpager to have 3 fragments with 3 diffent recyclers (actually you can use viewpager2 with a viewholder instead of making fragments)
have 3 recyclers (and you do a visibility.Gone every time user changes the tab)
In case I am not right, option 2 e 3 still solve your problem. I hope it helps!
p.s: you could also remove and insert observers everytime users changes tab, I find it to be less straightforward though.

LiveData observer onChanged is not called

I'm trying to use Room database in my Quiz application.
I couldn't get list of questions from database. here is the code I'm using :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.new_exam, container, false);
queViewModel=ViewModelProviders.of(this).get(QueViewModel.class);
queViewModel.getQuizList(examType).observe(this, new Observer<List<QueEnt>>() {
#Override
public void onChanged(List<QueEnt> queEnts) {
Log.e(TAG, "onChanged is called!"); // this line never shows in the Logcat
questionsList2 = queEnts;
}
});
and this is the ViewModel :
public class QueViewModel extends AndroidViewModel {
private QueRepository repository;
private LiveData<List<QueEnt>> quesList;
public QueViewModel(#NonNull Application application) {
super(application);
repository=new QueRepository(application);
quesList=repository.getQues();
}
public void insert(QueEnt queEnt){
repository.insert(queEnt);
}
public void delete(QueEnt queEnt){
repository.delete(queEnt);
}
public LiveData<List<QueEnt>> getQuizList(int examtype){
Log.e(TAG,"returning a list"); // this appears in the Logcat
return quesList;
}
}
The error I get is
Invalid index 0, size is 0
on questionsList2 , of course because the list was never populated. The onChanged method is not called, as it seems from the Logcat.
How can I fix this ?
Edit :
QueRepository file:
public class QueRepository {
private QueDao queDao;
private LiveData<List<QueEnt>> ques;
public QueRepository(Application application) {
QueDatabase database = QueDatabase.getInstance(application);
queDao = database.queDao();
ques = queDao.getQuesAll();
}
public void insert(QueEnt queEnt) {
new InsertQAsync(queDao).execute(queEnt);
}
public void update(QueEnt queEnt) {
new UpdateQAsync(queDao).execute(queEnt);
}
public void delete(QueEnt queEnt) {
new DeleteQAsync(queDao).execute(queEnt);
}
public LiveData<List<QueEnt>> getQues() {
return ques;
}
private static class InsertQAsync extends AsyncTask<QueEnt, Void, Void> {
private QueDao queDao;
private InsertQAsync(QueDao queDao) {
this.queDao = queDao;
}
#Override
protected Void doInBackground(QueEnt... queEnts) {
queDao.insert(queEnts[0]);
return null;
}
}
private static class UpdateQAsync extends AsyncTask<QueEnt, Void, Void> {
private QueDao queDao;
private UpdateQAsync(QueDao queDao) {
this.queDao = queDao;
}
#Override
protected Void doInBackground(QueEnt... queEnts) {
queDao.update(queEnts[0]);
return null;
}
}
private static class DeleteQAsync extends AsyncTask<QueEnt, Void, Void> {
private QueDao queDao;
private DeleteQAsync(QueDao queDao) {
this.queDao = queDao;
}
#Override
protected Void doInBackground(QueEnt... queEnts) {
queDao.delete(queEnts[0]);
return null;
}
}
}
And QueDao :
#Dao
public interface QueDao {
#Insert
void insert(QueEnt queEnt);
#Update
void update(QueEnt queEnt);
#Delete
void delete(QueEnt queEnt);
#Query("SELECT * FROM questions LIMIT 30" )
LiveData<List<QueEnt>> getQuesAll();
}
And Database :
#Database(entities = {QueEnt.class}, version = 1)
public abstract class QueDatabase extends RoomDatabase {
public static QueDatabase instance;
public static synchronized QueDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(), QueDatabase.class, "que_database")
.fallbackToDestructiveMigration()
.addCallback(roomCallback)
.build();
}
return instance;
}
public abstract QueDao queDao();
private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
#Override
public void onCreate(#NonNull SupportSQLiteDatabase db) {
super.onCreate(db);
new PopulateDbAsync(instance).execute();
}
};
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
private QueDao queDao;
private PopulateDbAsync(QueDatabase db) {
queDao = db.queDao();
}
#Override
protected Void doInBackground(Void... voids) {
queDao.insert(new QueEnt(91, 93, "Question 1?", " Answer 1", "Answer2 ", "Answer 3 ", " Answer4 ", 2, 2, 1,0,0,0,0,0,"","","","",""));
queDao.insert(new QueEnt(93, 95, "Question 2?", " Answer 1", "Answer2 ", "Answer 3 ", " Answer4 ", 3, 2, 4,0,0,0,0,0,"","","","",""));
return null;
}
}
}

How to show data from SQLite with CRUD in Android Studio?

Hi I'm doing an app and I made the database but I don't know how to read it to show in a listview for example I have a table CategoriaEntradas and I need to show all the data in a listview but I don't understand very well how it works all the classes
This is my Dao class
#Dao
public interface CategoriaEntradasDao {
#Insert
void insert(CategoriaEntradas categoriaEntradas);
#Update
void update(CategoriaEntradas categoriaEntradas);
#Delete
void delete(CategoriaEntradas categoriaEntradas);
#Query("DELETE FROM CategoriaEntradas")
void deleteAll();
#Query("SELECT * FROM CategoriaEntradas")
LiveData<List<CategoriaEntradas>> getAll();
#Query("SELECT * FROM CategoriaEntradas WHERE IdCategoria =:Id")
LiveData<CategoriaEntradas> getOne(int Id);
}
This is my Entity class
#Entity(tableName = "CategoriaEntradas")
public class CategoriaEntradas {
#PrimaryKey(autoGenerate = true)
#NonNull
#ColumnInfo(name = "IdCategoria")
private Integer _idCategoria;
#NonNull
#ColumnInfo(name = "Name")
private String _name;
#NonNull
#ColumnInfo(name = "Image")
private String _image;
public CategoriaEntradas(#NonNull String name, #NonNull String image) { _name = name; _image = image;}
public void set_idCategoria(Integer _idCategoria){
this._idCategoria = _idCategoria;
}
#NonNull
public Integer getIdCategoria() {
return _idCategoria;
}
#NonNull
public String getName() {
return _name;
}
#NonNull
public String getImage() {
return _image;
}
}
My Repository class
public class CategoriaEntradasRepository {
private CategoriaEntradasDao categoriaEntradasDao;
private LiveData<List<CategoriaEntradas>> listLiveData;
public CategoriaEntradasRepository(Application application) {
Database db = Database.getDatabase(application);
categoriaEntradasDao = db.categoriaEntradasDao();
listLiveData = categoriaEntradasDao.getAll();
}
public LiveData<List<CategoriaEntradas>> getAll() {
return listLiveData;
}
public LiveData<CategoriaEntradas> getOne(int Id) {
return categoriaEntradasDao.getOne(Id);
}
public void insert (CategoriaEntradas categoriaEntradas) {
new CategoriaEntradasRepository.insertAsyncTask(categoriaEntradasDao).execute(categoriaEntradas);
}
private static class insertAsyncTask extends AsyncTask<CategoriaEntradas, Void, Void> {
private CategoriaEntradasDao entradasDao;
insertAsyncTask(CategoriaEntradasDao dao) {
entradasDao = dao;
}
#Override
protected Void doInBackground(final CategoriaEntradas... params) {
entradasDao.insert(params[0]);
return null;
}
}
public void update(final CategoriaEntradas categoriaEntradas){
new CategoriaEntradasRepository.updateAsyncTask(categoriaEntradasDao).execute(categoriaEntradas);
}
private static class updateAsyncTask extends AsyncTask<CategoriaEntradas, Void, Void>{
private CategoriaEntradasDao entradasDao;
updateAsyncTask(CategoriaEntradasDao dao) {
entradasDao = dao;
}
#Override
protected Void doInBackground(final CategoriaEntradas... params){
entradasDao.update(params[0]);
return null;
}
}
public void delete(final CategoriaEntradas categoriaEntradas) {
new CategoriaEntradasRepository.deleteAsyncTask(categoriaEntradasDao).execute(categoriaEntradas);
}
public void delete(final int Id) {
final LiveData<CategoriaEntradas> categoriaEntradas = getOne(Id);
if (categoriaEntradas != null) {
new CategoriaEntradasRepository.deleteAsyncTask(categoriaEntradasDao).execute(categoriaEntradas.getValue());
}
}
private static class deleteAsyncTask extends AsyncTask<CategoriaEntradas, Void, Void>{
private CategoriaEntradasDao entradasDao;
deleteAsyncTask(CategoriaEntradasDao dao) {
entradasDao = dao;
}
#Override
protected Void doInBackground(final CategoriaEntradas... params){
entradasDao.delete(params[0]);
return null;
}
}
}
And my ViewModel class
public class CategoriaEntradasViewModel extends AndroidViewModel {
private CategoriaEntradasRepository repository;
private LiveData<List<CategoriaEntradas>> listLiveData;
public CategoriaEntradasViewModel (Application application) {
super(application);
repository = new CategoriaEntradasRepository(application);
listLiveData = repository.getAll();
}
public LiveData<List<CategoriaEntradas>> getAll() { return listLiveData; }
public LiveData<CategoriaEntradas> getOne(int Id) { return repository.getOne(Id); }
public void insert(CategoriaEntradas categoriaEntradas) { repository.insert(categoriaEntradas); }
public void update(CategoriaEntradas categoriaEntradas){ repository.update(categoriaEntradas);}
public void delete(CategoriaEntradas categoriaEntradas) {repository.delete(categoriaEntradas);}
public void delete(int Id) {repository.delete(Id);}
}
Try this at your Activity or fragment that have your listview.
CategoriaEntradasViewModel mViewModel = ViewModelProviders.of(this).get(CategoriaEntradasViewModel.class);
mViewModel.getAll().observe(this, new Observer<List<CategoriaEntradas>>() {
#Override
public void onChanged(List<CategoriaEntradas> categoriaEntradas) {
adapter = new YourListViewAdapter(this, categoriaEntradas);
listview.setAdapter(adapter);
}
}
Yes, if you have custom list item view. Its similar to array adapter.

Categories

Resources