I am trying to update my database using Room persistence Library and Livedata. I am very new to java, so, with the manual and various tutorial, I have setup the DAO, entity etc. But I am still struggling with how to actually add the data.
This is my database defination:
#Entity
public class PlaceSaved {
#PrimaryKey(autoGenerate = true)
private int id;
private String place;
private String lati;
private String longi;
public PlaceSaved(String place, String lati, String longi) {
this.place = place;
this.lati = lati;
this.longi = longi;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getLongi() {
return longi;
}
public void setLongi(String longi) {
this.longi = longi;
}
public String getLati() {
return lati;
}
public void setLati(String lati) {
this.lati = lati;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
DAO
#Dao
public interface DatabaseInterface {
#Query("SELECT * FROM placesaved")
LiveData<List<PlaceSaved>> getAllItems();
#Insert
void insertAll(PlaceSaved... placeSaveds);
#Delete
void delete(PlaceSaved... placeSaveds);
#Update
void update(PlaceSaved... placeSaveds);
}
Adapter
public class PlacesAdapter extends RecyclerView.Adapter<PlacesAdapter.RecyclerViewHolder>{
private List<PlaceSaved> items;
private View.OnClickListener ClickListener;
public PlacesAdapter(List<PlaceSaved> items){//}, View.OnClickListener ClickListener) {
this.items = items;
//this.ClickListener = ClickListener;
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.places_list_item, parent, false));
}
#Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
PlaceSaved placeSaved = items.get(position);
holder.itemTextView.setText(placeSaved.getPlace());
holder.nameTextView.setText(placeSaved.getLati());
holder.dateTextView.setText(placeSaved.getLongi());
/* holder.dateTextView.setText(borrowModel.getBorrowDate().toLocaleString().substring(0, 11));
holder.itemView.setTag(borrowModel);
holder.itemView.setOnLongClickListener(longClickListener);*/
}
#Override
public int getItemCount() {
return items.size();
}
public void addItems(List<PlaceSaved> items) {
this.items = items;
notifyDataSetChanged();
}
static class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView itemTextView;
private TextView nameTextView;
private TextView dateTextView;
RecyclerViewHolder(View view) {
super(view);
itemTextView = (TextView) view.findViewById(R.id.firstLine);
nameTextView = (TextView) view.findViewById(R.id.secondLine);
dateTextView = (TextView) view.findViewById(R.id.longitude);
}
}
}
and the ViewModel
public class PlacesViewModel extends AndroidViewModel {
private final LiveData<List<PlaceSaved>> PlacedatabaseList;
private PlaceDatabase appDatabase;
public PlacesViewModel(Application application) {
super(application);
appDatabase = PlaceDatabase.getDatabase(this.getApplication());
PlacedatabaseList = appDatabase.PlacedatabaseInterface().getAllItems();
}
public LiveData<List<PlaceSaved>> getPlaceList() {
return PlacedatabaseList;
}
public void deleteItem(PlaceSaved placeSaved) {
new deleteAsyncTask(appDatabase).execute(placeSaved);
}
private static class deleteAsyncTask extends AsyncTask<PlaceSaved, Void, Void> {
private PlaceDatabase db;
deleteAsyncTask(PlaceDatabase appDatabase) {
db = appDatabase;
}
#Override
protected Void doInBackground(final PlaceSaved... params) {
db.PlacedatabaseInterface().delete(params[0]);
return null;
}
}
}
Now, I am trying to add an item to database with OnClick of a fab as:
public class PlacesActivity extends AppCompatActivity {
private PlacesViewModel viewModel;
private PlacesAdapter placesAdapter;
private RecyclerView recyclerView;
FloatingActionButton fab, fab1, fab2, fab3;
LinearLayout fabLayout1, fabLayout2, fabLayout3;
boolean isFABOpen = false;
View fabBGLayout;
PlaceDatabase db;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.places_layout);
viewModel = ViewModelProviders.of(this).get(PlacesViewModel.class);
Runnable r =new Runnable() {
#Override
public void run() {
recyclerView = findViewById(R.id.my_recycler_view);
placesAdapter = new PlacesAdapter(new ArrayList<PlaceSaved>());//, this);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplication()));
recyclerView.setAdapter(placesAdapter);
}
};
Thread newThread = new Thread(r);
newThread.start();
fab1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Dialog
/*
Add location manually
*/
AlertDialog.Builder placeLLDialog = new AlertDialog.Builder(PlacesActivity.this);
LayoutInflater inflater = getLayoutInflater();
final View view = inflater.inflate(R.layout.place_add_dialog, null);
placeLLDialog.setView(view);
final EditText todo = view.findViewById(R.id.placeN);
final EditText time = view.findViewById(R.id.placell);
final EditText longi = view.findViewById(R.id.placell2);
placeLLDialog.setTitle("Add Place with Latitude and Longitude")
.setPositiveButton("Add", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (!todo.getText().toString().equals("") &&
!time.getText().toString().equals("") &&
!longi.getText().toString().equals("")) {
Snackbar.make(view, "Running", Snackbar.LENGTH_LONG).show();
/* HERE I AM TRYING TO ADD THE DATA, WHICH IS NOT WORKING
final PlaceSaved placeSaved = new PlaceSaved(todo.getText().toString(),
time.getText().toString(), longi.getText().toString());
AsyncTask.execute(new Runnable() {
#Override
public void run() {
db.databaseInterface().insertAll(placeSaved);
items = db.databaseInterface().getAllItems();
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter = new PlacesAdapter(items, db, null);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
closeFABMenu();
}
});
}
});*/
}
}
})
.setNegativeButton("Cancel", null);
AlertDialog alertDialog = placeLLDialog.create();
alertDialog.show();
alertDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}
});
since I am very new to java, I can't find out how to add the data to the database, which is inside fab1.setOnClickListner.
I will be grateful if someone kindly helps.
UPDATE
I forgot to add database itself, here it is:
#Database(entities = {PlaceSaved.class},version = 1)
public abstract class PlaceDatabase extends RoomDatabase {
private static PlaceDatabase INSTANCE;
public static PlaceDatabase getDatabase(Context context){
if (INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), PlaceDatabase.class,
"places_db").build();
}
return INSTANCE;
}
public abstract DatabaseInterface PlacedatabaseInterface();
Create Class AddBorrowViewModel
public class AddBorrowViewModel extends AndroidViewModel
{
private PlaceDatabase appDatabase;
public AddBorrowViewModel(#NonNull Application application) {
super(application);
appDatabase = PlaceDatabase.getDatabase(this.getApplication());
}
public void addBorrow(PlaceSaved placedSaved)
{
new addAsyncTask(appDatabase).execute(placedSaved);
}
private class addAsyncTask extends AsyncTask<PlaceSaved , Void, Void>
{
private PlaceDatabase appDatabase_;
addAsyncTask(PlaceDatabase appDatabase)
{
appDatabase_ = appDatabase;
}
#Override
protected Void doInBackground(PlaceSaved... placedSaved) {
appDatabase_.itemAndPersonModel().addBorrow(placedSaved[0]);
return null;
}
}
}
add this variable in your PlacesActivity
private AddBorrowViewModel addBorrowViewModel;
in OnCreate add this
addBorrowViewModel = ViewModelProviders.of(this).get(AddBorrowViewModel.class);
in onClickListener Of alertDilaog after snackbar
addBorrowViewModel.addBorrow(new PlaceSaved(
todo.getText().toString(),
time.getText().toString(), longi.getText().toString()
));
In your PlaceDatabase add
public abstract Dao itemAndPersonModel();
Related
I have this adapter with a button that dependent on if a object already exists in my Room Database or not will have a differente behavior when it´s clicked. Basically what I want to do is if the object exists I want to remove it. In case it doesn´t I want to add it to my database. I created this method in Dao and a Task to check the existence. Since the Task is asynchronous ,how can I do the verification?
My Adapter
public class RestaurantAdapter extends RecyclerView.Adapter<RestaurantAdapter.RestaurantViewHolder> {
private Context mContext;
private List<Restaurant_> mRestaurants;
private Activity act;
private FirebaseAuth mAuth;
private String currentUserId;
private View rView;
public RestaurantAdapter(Context context, List<Restaurant_> restaurants, Activity activity) {
mRestaurants = restaurants;
mContext = context;
act = activity;
}
#Override
public RestaurantViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Get layout inflater from context
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
// Inflate layout
rView = inflater.inflate(R.layout.item_restaurant, parent, false);
// Return a new holder instance
return new RestaurantViewHolder(rView);
}
#Override
public void onBindViewHolder(RestaurantViewHolder viewHolder, final int position) {
// Get the data model based on position
final Activity activity = act;
final Restaurant_ restaurant = mRestaurants.get(position);
mAuth = FirebaseAuth.getInstance();
currentUserId = mAuth.getCurrentUser().getUid();
final TextView name = viewHolder.nameTextView;
name.setText(restaurant.getName());
final TextView rating = viewHolder.ratingTextView;
rating.setText((restaurant.getUserRating().getAggregateRating()));
final TextView distance = viewHolder.distanceTextView;
distance.setText(String.valueOf(restaurant.getDistance()) + " Km");
final ImageButton addToWishlistButton = viewHolder.addToWishlistButton;
addToWishlistButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Wishlist wishlist = new Wishlist(currentUserId, restaurant.getId());
//if(alreadyExists){
//RemoveWLTask rlt=new RemoveWLTask(wishlist,activity);
//rlt.execute()
// }
// else{
AddWLTask wlt = new AddWLTask(wishlist, activity);
wlt.execute();
//}
}
});
final ImageButton addToFavoritesButton = viewHolder.addToFavoritesButton;
addToFavoritesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addToFavoritesButton.getBackground().setTint(activity.getResources().getColor(R.color.red));
addToFavorites();
}
});
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LiveFragment.getListener().onRestaurantClicked(restaurant.getId());
}
});
}
#Override
public int getItemCount() {
return mRestaurants.size();
}
public class RestaurantViewHolder extends RecyclerView.ViewHolder {
public TextView nameTextView;
public TextView ratingTextView;
public TextView distanceTextView;
public ImageButton addToWishlistButton;
public ImageButton addToFavoritesButton;
public RestaurantViewHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.restaurantName);
ratingTextView = itemView.findViewById(R.id.restaurantRating);
distanceTextView = itemView.findViewById(R.id.restaurantDistance);
addToWishlistButton = itemView.findViewById(R.id.button_wishlist);
addToFavoritesButton = itemView.findViewById(R.id.button_favorites);
}
}
}
My DAO
#Dao
public interface DAO {
#Insert
public void addToWishlist(Wishlist wishlist);
#Delete
public void deleteFromWishlist(Wishlist wishlist);
#Query("Select restaurantId From wishlist Where userId=:id")
public String[] loadWishlist(String id);
#Query("Select restaurantId From wishlist where userId=:userID AND restaurantId=:restaurantID")
public String[]checkExists(String userID, String restaurantID);
}
##My Task ##
public class CheckWLTask extends AsyncTask<Void, Void, Void> {
private DB db;
private Activity activity;
private String userId;
private String restaurantId;
private String [] response;
public CheckWLTask(Activity activity, String idUser, String idRestaurant) {
this.activity = activity;
this.userId = idUser;
this.restaurantId = idRestaurant;
db = Room.databaseBuilder(activity.getApplicationContext(), DB.class, "sample-db").build();
}
#Override
protected Void doInBackground(Void... voids) {
while (!isCancelled()) {
this.response=db.daoAcess().checkExists(userId,restaurantId);
break;
}
return null;
}
}
``
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
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.
friends...
In my project, I am creating a list of images from the server and showing in Recyclerview.
now I want to remove a particular item from the list when I click on the verify button.
I tried to hide holder.itemview but its see again when I scroll.
I just want to remove or hide that item which is verified once.
here is my code :
1) Main activity
public class MainActivity extends AppCompatActivity {
private static final String url = "www.mysite.com/api/api-id-list.php?action=imgs";
private ProgressDialog mDetailProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main_activity);
LoadRecyclerView();
}
private void LoadRecyclerView() {
mDetailProgress = new ProgressDialog(this);
mDetailProgress.setTitle("Loading images");
mDetailProgress.setMessage("Please Wait...");
mDetailProgress.setCanceledOnTouchOutside(false);
mDetailProgress.show();
final RecyclerView imgList = (RecyclerView) findViewById(R.id.imgList);
imgList.setLayoutManager(new LinearLayoutManager(this));
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
Image[] images = gson.fromJson(response, Image[].class);
imgList.setAdapter(new ImageAdapter(MainActivity.this, images));
mDetailProgress.dismiss();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getBaseContext(), "Something went wrong..!", Toast.LENGTH_LONG);
}
});
RequestQueue queue = Volley.newRequestQueue(this);
queue.add(request);
}}
2) ImageAdapter
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ImageViewHolder> {
private ProgressDialog mDetailProgress;
private Context context;
private Image[] data;
Button btn_ban, btn_verify;
private View view;
public ImageAdapter (Context context, Image[] data) {
this.context = context;
this.data = data;
}
#NonNull
#Override
public ImageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int i) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
view = inflater.inflate(R.layout.single_item, parent, false);
return new ImageViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ImageViewHolder holder, final int position) {
final Image imagelist = data[position];
holder.userCode.setText(imagelist.getCode());
Glide.with(holder.userImage.getContext()).load(imagelist.getIdPhoto()).into(holder.userImage);
btn_verify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.itemView.setVisibility(View.GONE);
}
});
}
#Override
public int getItemCount() { return data.length; }
public class ImageViewHolder extends RecyclerView.ViewHolder {
TextView userCode;
ImageView userImage;
public ImageViewHolder(#NonNull View itemView) {
super(itemView);
userImage = (ImageView) itemView.findViewById(R.id.card_iv_img);
userCode = (TextView) itemView.findViewById(R.id.card_tv_code);
btn_ban = (Button) itemView.findViewById(R.id.btn_ban);
btn_verify = (Button) itemView.findViewById(R.id.btn_verify);
}
}}
3) Image.java
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Image {
#SerializedName("per_ID")
#Expose
private String perID;
#SerializedName("code")
#Expose
private String code;
#SerializedName("first_nm")
#Expose
private String firstNm;
#SerializedName("last_nm")
#Expose
private String lastNm;
#SerializedName("photo_ID")
#Expose
private String photoID;
#SerializedName("id_photo")
#Expose
private String idPhoto;
public String getPerID() {
return perID;
}
public void setPerID(String perID) {
this.perID = perID;
}
public Image withPerID(String perID) {
this.perID = perID;
return this;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Image withCode(String code) {
this.code = code;
return this;
}
public String getFirstNm() {
return firstNm;
}
public void setFirstNm(String firstNm) {
this.firstNm = firstNm;
}
public Image withFirstNm(String firstNm) {
this.firstNm = firstNm;
return this;
}
public String getLastNm() {
return lastNm;
}
public void setLastNm(String lastNm) {
this.lastNm = lastNm;
}
public Image withLastNm(String lastNm) {
this.lastNm = lastNm;
return this;
}
public String getPhotoID() {
return photoID;
}
public void setPhotoID(String photoID) {
this.photoID = photoID;
}
public Image withPhotoID(String photoID) {
this.photoID = photoID;
return this;
}
public String getIdPhoto() {
return idPhoto;
}
public void setIdPhoto(String idPhoto) {
this.idPhoto = idPhoto;
}
public Image withIdPhoto(String idPhoto) {
this.idPhoto = idPhoto;
return this;
}}
First make data not array, but List, so it's easy to remove item;
Secondly set listener for verify button inside ViewHolder and inside OnClick remove item and notify adapter.
btn_verify.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
data.remove(position);
notifyItemRemoved(position);
}
});
Note: Setting OnClickListener inside ViewHolder makes sure that only correct item is removed by using getAdapterPosition() to get correct position.
Position provided by onBindViewHolder might be invalid after new items are inserted.
I am trying to make a call to this api and am having difficulty as the response.body() is returning null.
http://demo.museum.vebrary.vn/api/stuff/getall
I want to get stuff name of list and show to my recyclerview.
My model:
public class SOAnswersResponse {
#SerializedName("StuffModels")
#Expose
private List<StuffModel> stuffModels = null;
public List<StuffModel> getStuffModels() {
return stuffModels;
}
public void setStuffModels(List<StuffModel> stuffModels) {
this.stuffModels = stuffModels;
}
and
public class StuffModel {
#SerializedName("STUFFID")
#Expose
private Integer sTUFFID;
#SerializedName("STUFFCODE")
#Expose
private String sTUFFCODE;
#SerializedName("STUFFNAME")
#Expose
private String sTUFFNAME;
#SerializedName("STUFFNOTE")
#Expose
private String sTUFFNOTE;
#SerializedName("STUFFORDER")
#Expose
private Integer sTUFFORDER;
#SerializedName("CUSTOMERID")
#Expose
private String cUSTOMERID;
#SerializedName("EXHIBITS")
#Expose
private List<Object> eXHIBITS = null;
Json response
{
"StuffModels":[
{
"STUFFID":2,
"STUFFCODE":"Gi",
"STUFFNAME":"Giấy",
"STUFFNOTE":"",
"STUFFORDER":2,
"CUSTOMERID":"CAMAU",
"EXHIBITS":[
]
},
ApiUtils Class
public class ApiUtils {
private ApiUtils() {
}
public static final String BASE_URL = "http://demo.museum.vebrary.vn/api/";
public static SOService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SOService.class);
}
}
Service interface
public interface SOService {
#GET("/stuff/getall")
Call<SOAnswersResponse> getAnswers();
}
RetrofitClient Class
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
My RecyclerView adapter
public class CategogyNameRecyclerViewAdapter extends RecyclerView.Adapter<CategogyNameRecyclerViewAdapter.ViewHolder> {
private List<StuffModel> mItems;
private Context mContext;
private PostItemListener mItemListener;
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView titleTv;
PostItemListener mItemListener;
public ViewHolder(View itemView, PostItemListener postItemListener) {
super(itemView);
titleTv = itemView.findViewById(R.id.tvListMenuCategogy);
this.mItemListener = postItemListener;
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
StuffModel item = getItem(getAdapterPosition());
this.mItemListener.onPostClick(item.getSTUFFID());
notifyDataSetChanged();
}
}
public CategogyNameRecyclerViewAdapter(Context context, List<StuffModel> posts, PostItemListener itemListener) {
mItems = posts;
mContext = context;
mItemListener = itemListener;
}
#Override
public CategogyNameRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View postView = inflater.inflate(R.layout.item_list_text, parent, false);
ViewHolder viewHolder = new ViewHolder(postView, this.mItemListener);
return viewHolder;
}
#Override
public void onBindViewHolder(CategogyNameRecyclerViewAdapter.ViewHolder holder, int position) {
StuffModel item = mItems.get(position);
TextView textView = holder.titleTv;
textView.setText(item.getSTUFFNAME());
}
#Override
public int getItemCount() {
return mItems.size();
}
public void updateAnswers(List<StuffModel> items) {
mItems = items;
notifyDataSetChanged();
}
private StuffModel getItem(int adapterPosition) {
return mItems.get(adapterPosition);
}
public interface PostItemListener {
void onPostClick(long id);
}
}
And my main activity
public class Testttt extends AppCompatActivity {
private CategogyNameRecyclerViewAdapter mAdapter;
private RecyclerView mRecyclerView;
private SOService mService;
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView(R.layout.test );
mService = ApiUtils.getSOService();
mRecyclerView = (RecyclerView) findViewById(R.id.rcvCategogyNameMenuTest);
mAdapter = new CategogyNameRecyclerViewAdapter(this, new ArrayList<StuffModel>(0), new CategogyNameRecyclerViewAdapter.PostItemListener() {
#Override
public void onPostClick(long id) {
Toast.makeText(Testttt.this, "Post id is" + id, Toast.LENGTH_SHORT).show();
}
});
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
mRecyclerView.addItemDecoration(itemDecoration);
loadAnswers();
}
public void loadAnswers() {
mService.getAnswers().enqueue(new Callback<SOAnswersResponse>() {
#Override
public void onResponse(Call<SOAnswersResponse> call, Response<SOAnswersResponse> response) {
Toast.makeText(Testttt.this, "333333333333333333"+response.body(), Toast.LENGTH_SHORT).show();
if(response.isSuccessful()) {
mAdapter.updateAnswers(response.body().getStuffModels());
Log.d("AnswersPresenter", "posts loaded from API");
}else {
int statusCode = response.code();
}
}
#Override
public void onFailure(Call<SOAnswersResponse> call, Throwable t) {
showErrorMessage();
Log.d("AnswersPresenter", "error loading from API");
}
});
}
public void showErrorMessage() {
Toast.makeText(this, "Error loading posts", Toast.LENGTH_SHORT).show();
}
}
The first thing that came in my mind:
Your
public static final String BASE_URL = "http://demo.museum.vebrary.vn/api/";
has a "/" at the the end and your
#GET("/stuff/getall")
Call<SOAnswersResponse> getAnswers();
starts with a "/". So there is a double backslash in the url that might leads to the 404 code. Does this solve the problem?
When i call your URL i receive XML. Maybe the API is not configured correctly?
Change your Service interface
public interface SOService {
#GET("stuff/getall")
Call<SOAnswersResponse> getAnswers();
}
it occurred because you have use start with backslash it already added in your base url