RecyclerView doesn't inflate, rather updates the same view? - java

I have an activity to implement a to-do list, containing a recyclerview with each item being a checkbox and textview, and each task is added from an edittext.
It stores data using Realm.io. The behaviour that I keep getting is that the single element in the recyclerview merely get updated, and not inflated! Please help.
TasksActivity -
public class TasksActivity extends AppCompatActivity implements View.OnClickListener{
TextView courseTitle;
RecyclerView TaskList;
EditText addTask;
Button addButton;
String transName; //Transferred Course name from MainActivity
TaskAdapter TA;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tasks);
courseTitle = findViewById(R.id.CourseName);
TaskList = findViewById(R.id.TaskListRV);
TaskList.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
addTask = findViewById(R.id.InputTask);
addButton = findViewById(R.id.AddTaskButton);
//Course name is the obtained from the previous acivity.
transName =getIntent().getExtras().getString("CourseName");
courseTitle.setText(transName);
TA = new TaskAdapter(transName);
TaskList.setAdapter(TA);
addButton.setOnClickListener(this);
}
#Override
public void onClick(View view) {
String task = addTask.getText().toString();
// Checking if the text is empty.
boolean flag = false;
for(int i = 0;i<task.length();i++)
{
if(task.charAt(i)!=' ')
flag = true;
}
if(!flag || task.equals(""))
{
Toast emptyWarning = Toast.makeText(getApplicationContext(),"Task cannot be Empty!",Toast.LENGTH_SHORT);
emptyWarning.show();
}
else
{
addTask.setText("");
TA.addNewTask(task);
}
}
}
TasksAdapter -
public class TaskAdapter extends RecyclerView.Adapter<TaskViewHolder> implements RealmChangeListener<RealmResults<TaskModel>>
{
private ArrayList<TaskModel> TaskList;
private String course;
private final Realm realm;
public TaskAdapter(String course)
{
this.course = course;
this.TaskList = new ArrayList<>();
realm = Realm.getDefaultInstance();
loadTaskData();
}
void loadTaskData()
{
RealmResults<TaskModel> taskModelRealmResults = realm.where(TaskModel.class).equalTo("courseName",course).findAll();
taskModelRealmResults.addChangeListener(this);
for(TaskModel iTM : taskModelRealmResults)
{
TaskList.add(realm.copyFromRealm(iTM));
}
notifyDataSetChanged();
}
#Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view= layoutInflater.inflate(R.layout.item_task,parent,false);
TaskViewHolder Tvh = new TaskViewHolder(view);
return Tvh;
}
#Override
public void onBindViewHolder(TaskViewHolder holder, int position) {
holder.populateTask(TaskList.get(position));
}
#Override
public int getItemCount() {
return TaskList.size();
}
public void addNewTask(String task)
{
TaskModel newTaskObj = new TaskModel(task,course,false);
TaskList.add(newTaskObj);
notifyDataSetChanged();
realm.beginTransaction();
realm.insertOrUpdate(newTaskObj);
realm.commitTransaction();
}
#Override
public void onChange(RealmResults<TaskModel> taskModels) {
taskModels = realm.where(TaskModel.class).equalTo("courseName",course).findAll();
this.TaskList = new ArrayList<>();
for(TaskModel iTM : taskModels)
{
this.TaskList.add(realm.copyFromRealm(iTM));
}
notifyDataSetChanged();
}
}
TaskViewHolder and TaskModel - (in case you might need them)
public class TaskModel extends RealmObject {
String task;
#PrimaryKey
String courseName;
boolean isDone;
public TaskModel() {
task = "";
courseName = "";
isDone = false;
}
public TaskModel(String task, String courseName, boolean isDone) {
this.task = task;
this.courseName = courseName;
this.isDone = isDone;
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public boolean isDone() {
return isDone;
}
public void setDone(boolean done) {
isDone = done;
}
}
public class TaskViewHolder extends RecyclerView.ViewHolder {
CheckBox isdone;
TextView Taskname;
public TaskViewHolder(View itemView) {
super(itemView);
isdone = itemView.findViewById(R.id.TaskCheckBox);
Taskname = itemView.findViewById(R.id.TaskName);
}
void populateTask(final TaskModel T)
{
Taskname.setText(T.getTask());
isdone.setChecked(T.isDone());
isdone.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
T.setDone(isdone.isChecked());
}
});
}
}

I advise you to use Realm Android dapter, this adapter is taking care of updating your app UI. Don't need to implement OnChangeListener, your list will be automatically updated after insertion, deletion or edition
Use findAllAsync in order to not block the UI thread
OrderedRealmCollection<TaskModel> taskModels = realm.where(TaskModel.class).equalTo("courseName", course).findAllAsync();
public RealmAdapter(OrderedRealmCollection<TaskModel> data) {
super(data, true);
}
EDIT:
Also always do the process using Async method when it's possible. You can replace your addNewTask method by:
public void addNewTask(String task) {
final TaskModel newTaskObj = new TaskModel(task, course, false);
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(newTaskObj);
}
});
}
Yous should have something like this:
TasksActivity
public class TasksActivity extends AppCompatActivity implements View.OnClickListener {
private EditText addTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tasks);
String transName = getIntent().getExtras().getString("CourseName");
TextView courseTitle = findViewById(R.id.CourseName);
courseTitle.setText(transName);
addTask = findViewById(R.id.InputTask);
findViewById(R.id.AddTaskButton).setOnClickListener(this);
OrderedRealmCollection<TaskModel> taskModels = Realm.getDefaultInstance().where(TaskModel.class).equalTo("courseName", transName).findAllAsync()
TaskAdapter adapter = new TaskAdapter(this, taskModels);
RecyclerView taskList = findViewById(R.id.TaskListRV);
taskList.setLayoutManager(new LinearLayoutManager(this));
taskList.setAdapter(adapter);
}
#Override
public void onClick(View view) {
String task = addTask.getText().toString().trim();
if (task.trim().isEmpty()) {
Toast emptyWarning = Toast.makeText(getApplicationContext(),"Task cannot be Empty!",Toast.LENGTH_SHORT);
emptyWarning.show();
return;
}
addTask.setText("");
addNewTask(task);
}
private void addNewTask(String task) {
final TaskModel newTaskObj = new TaskModel(task, course, false);
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(newTaskObj);
}
});
}
}
And TaskAdapter:
public class TaskAdapter extends RealmRecyclerViewAdapter<TaskModel, TaskViewHolder> {
private LayoutInflater layoutInflater
public TaskAdapter(Context context, OrderedRealmCollection<TaskModel> taskModels) {
super(taskModels, true);
this.layoutInflater = LayoutInflater.from(context);
}
#Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new TaskViewHolder(layoutInflater.inflate(R.layout.item_task , parent, false));
}
#Override
public void onBindViewHolder(TaskViewHolder holder, int position) {
holder.populateTask(getItem(position));
}
}

OP here. I ended up using the standard ReacyclerView.Adapter.
The problem was with the usage of Realm's insertOrUpdate method, when the #PrimaryKey was courseName which thus caused it to indeed update the same object and not create a new one!
insert() should have been used.
Here is the insert task method -
public void addNewTask(String task)
{
boolean flag = false;
for(int i = 0;i<TaskList.size();i++)
{
if(task.equals(TaskList.get(i).getTask()))
{
Toast.makeText(context,"Task already exists!",Toast.LENGTH_SHORT).show();
flag = true;
break;
}
}
if(!flag)
{
TaskModel newTaskObj = new TaskModel();
newTaskObj.setTask(task);
newTaskObj.setDone(false);
newTaskObj.setCourseName(course);
TaskList.add(newTaskObj);
notifyDataSetChanged();
realm.beginTransaction();
realm.insert(newTaskObj);
realm.commitTransaction();
} }
The entire project can be found here, do check it out -
https://github.com/Hariram-R/ToDoList-App

Related

Show the latest item firest in Firebase ui Realtime database [duplicate]

I try to use the FirebaseUI-Realtime Database Android lib to simply display a data set in a viepager2 with recycler-view adapter
When I get the data, I got the oldest data first, and i need to show the latest first . So I need a reverse order. How i can do it in RecyclerView adapter?
MainActivity.java
public class MainActivity extends AppCompatActivity {
ViewPager2 viewPager2;
videoadapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
viewPager2 = (ViewPager2) findViewById(R.id.vpager);
FirebaseRecyclerOptions<videomodel> options = new FirebaseRecyclerOptions.Builder<videomodel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("videos"), videomodel.class).build();
adapter = new videoadapter(options);
viewPager2.setAdapter(adapter);
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
}
videoadapter.java
public class videoadapter extends
FirebaseRecyclerAdapter<videomodel, videoadapter.myviewholder> {
private Context context;
private AppCompatActivity activity;
private Timer _timer = new Timer();
private double positionc;
private TimerTask check;
private ProgressBar progressbar11;
private ViewPager2 viewPager;
public videoadapter(#NonNull FirebaseRecyclerOptions<videomodel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull myviewholder holder, int position, #NonNull videomodel model) {
holder.setdata(model);
holder.simpleExoPlayer.prepare();
}
#NonNull
#Override
public myviewholder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_video_row, parent, false);
return new myviewholder(view);
}
#Override
public void onViewAttachedToWindow(videoadapter.myviewholder holder) {
super.onViewAttachedToWindow(holder);
holder.playerView.getPlayer().seekTo(0);
holder.playerView.getPlayer().setPlayWhenReady(true);
holder.playerView.getPlayer().prepare();
}
#Override
public void onViewDetachedFromWindow(videoadapter.myviewholder holder) {
super.onViewDetachedFromWindow(holder);
holder.playerView.getPlayer().setPlayWhenReady(false);
holder.playerView.getPlayer().stop();
}
class myviewholder extends RecyclerView.ViewHolder {
PlayerView playerView;
SimpleExoPlayer simpleExoPlayer;
LinearLayout sec_mid;
ProgressBar progressbar1;
DefaultTrackSelector trackSelector;
ImageView play,pause;
TextView title,desc;
public myviewholder(#NonNull View view) {
super(view);
playerView = (PlayerView) view.findViewById(R.id.statusSliderVideo);
sec_mid = (LinearLayout) view.findViewById(R.id.sec_controlvid1);
progressbar1 = (ProgressBar) view.findViewById(R.id.progressbar11);
play = (ImageView) view.findViewById(R.id.exo_play);
pause = (ImageView) view.findViewById(R.id.exo_pause);
title = (TextView) view.findViewById(R.id.textVideoTitle);
desc = (TextView) view.findViewById(R.id.textVideoDescription);
}
void setdata(videomodel obj) {
progressbar1.getProgressDrawable().setColorFilter(Color.WHITE, android.graphics.PorterDuff.Mode.SRC_IN);
progressbar1.setIndeterminate(true);
title.setText(obj.getTitle());
desc.setText(obj.getDesc());
// get data
Uri videoUri = Uri.parse(obj.getUrl());
simpleExoPlayer = new SimpleExoPlayer.Builder(playerView.getContext()).build();
playerView.setPlayer(simpleExoPlayer);
playerView.setKeepScreenOn(true);
MediaItem mediaItem = MediaItem.fromUri(videoUri);
simpleExoPlayer.setMediaItem(mediaItem);
simpleExoPlayer.prepare();
playerView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View _view) {
if (simpleExoPlayer.isPlaying()) {
simpleExoPlayer.pause();
} else {
simpleExoPlayer.play();
}
}
});
simpleExoPlayer.addListener(new Player.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_BUFFERING) {
progressbar1.setIndeterminate(true);
} else {
progressbar1.setIndeterminate(false);
}
if (playbackState == Player.STATE_ENDED) {
simpleExoPlayer.seekTo(0);
simpleExoPlayer.setPlayWhenReady(true);
}
}
});
Activity activity = new Activity();
check = new TimerTask() {
#Override
public void run() {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
progressbar1.setMax((int) simpleExoPlayer.getDuration());
progressbar1.setProgress((int) simpleExoPlayer.getCurrentPosition());
}
});
}
};
_timer.scheduleAtFixedRate(check, (int) (0), (int) (1));
}
}
}
videomodel
public class videomodel {
String desc,title,url;
public videomodel(String desc, String title, String url) {
this.desc = desc;
this.title = title;
this.url = url;
}
videomodel()
{
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

How can I hide an ImageView on my RecyclerView for certain items based on a particular condition?

I have a RecyclerView with an ImageView being a part of the items. I want to hide the ImageView from an item in the RecyclerView if a certain condition is met. How can I do that? I am attaching the image of how I want it to look like.
I am just defining the ImageViews in my xml layout file, so I cannot figure out how to actually remove it based on a certain condition in my android activity. I am attaching the code for the adapter class and my activity as well.
Here is the code for my adapter class
Adapter Class
public class ReportAdapter extends RecyclerView.Adapter<ReportAdapter.ReportViewHolder> {
private ArrayList<ReportItem> reportlist;
private OnItemClickListener mListener;
private Context mContext;
public ReportAdapter(ArrayList<ReportItem> reportlist, Context context) {
this.reportlist = reportlist;
this.mContext = context;
}
public interface OnItemClickListener {
void onItemClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public static class ReportViewHolder extends RecyclerView.ViewHolder {
public TextView departureDate;
public TextView flightNumber;
public View relativelayout;
public ReportViewHolder(#NonNull View itemView, OnItemClickListener listener, Context context) {
super(itemView);
departureDate = itemView.findViewById(R.id.departureDaterecyclerview);
flightNumber = itemView.findViewById(R.id.flightnumberrecyclerview);
relativelayout = itemView.findViewById(R.id.relativeLayoutReports);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
}
}
}
});
}
}
#NonNull
#Override
public ReportViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.report_listing_item, parent, false);
ReportViewHolder rvh= new ReportViewHolder(v,mListener,mContext);
return rvh;
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
if(position%2==0){
holder.relativelayout.setBackgroundColor(mContext.getResources().getColor(R.color.reportlistingteal));
} else {
holder.relativelayout.setBackgroundColor(mContext.getResources().getColor(R.color.reportlistinglightteal));
}
holder.departureDate.setText((currentItem.getDepartureDate()));
holder.flightNumber.setText(currentItem.getFlightNumber());
}
Here is the code for my activity file
Activity file
public class ReportListingActivity extends AppCompatActivity {
private Button uploadAllBtn;
private EditText searchFlights;
private RecyclerView mRecyclerView;
private ReportAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
ArrayList<ReportItem> reportitems = new ArrayList<>();
private FlightViewModel flightViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_report_listing);
uploadAllBtn = findViewById(R.id.uploadAllReports);
searchFlights = findViewById(R.id.searchFlightText);
mRecyclerView = findViewById(R.id.recyclerView);
flightViewModel = new ViewModelProvider(this).get(FlightViewModel.class);
flightViewModel.getAllFlights().observe(this, new Observer<List<Flight>>() {
#Override
public void onChanged(List<Flight> flight_list) {
if (flight_list.size() == 0) return;
String flightno = flight_list.get(0).getFlightNumber();
String flightdate = flight_list.get(0).getDate();
String[] flight_details = new String[2];
flight_details[0]= flightno;
flight_details[1] = flightdate;
Log.v("pp", flight_details[0]);
for(int i = 0; i <flight_list.size();i++){
String flightnumber = flight_list.get(i).getFlightNumber();
String departuredate = flight_list.get(i).getDate();
reportitems.add(new ReportItem(flightnumber,departuredate));
}
mRecyclerView.getAdapter().notifyDataSetChanged();
flightViewModel.getAllFlights().removeObservers(ReportListingActivity.this);
}
});
mLayoutManager = new LinearLayoutManager(ReportListingActivity.this);
mAdapter = new ReportAdapter(reportitems, ReportListingActivity.this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
Report Item
public class ReportItem {
private String departureDate;
private String flightNumber;
public ReportItem(String departureDate, String flightNumber) {
this.departureDate = departureDate;
this.flightNumber = flightNumber;
}
public String getDepartureDate() {
return departureDate;
}
public String getFlightNumber() {
return flightNumber;
}
}
Add a boolean flag to your ReportItem class for each RecyclerView item. You will need to specify which rows show or hide this field when each item is created:
public class ReportItem {
private String departureDate;
private String flightNumber;
private Boolean showMailIcon;
public ReportItem(String departureDate, String flightNumber, Boolean showMailIcon) {
this.departureDate = departureDate;
this.flightNumber = flightNumber;
this.showMailIcon = showMailIcon
}
public String getDepartureDate() {
return departureDate;
}
public String getFlightNumber() {
return flightNumber;
}
public String getShowMailIcon() {
return showMailIcon;
}
}
Then update the onBindViewHolder() method override to use this flag to show/hide the ImageView:
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
if (currentItem.getShowMailIcon() == true) {
holder.mailIcon.setVisibility(View.VISIBLE);
} else {
holder.mailIcon.setVisibility(View.GONE);
}
//.......
}

How to get details when clicking on an item in a RecyclerView?

I am trying to get the details of the Recipe from which Recipe I have clicked in recycler view. I am using this to go to an edit/delete feature. Here is the code for my main activity.
The details that I am trying to get is getting the Name, Ingredients and method.
public class MainActivity extends AppCompatActivity implements RecipeListAdapter.OnItemClickListener {
private RecipeViewModel mRecipeViewModel;
public static final int NEW_WORD_ACTIVITY_REQUEST_CODE = 1;
public String Name;
public String Ingredients;
public String Method;
private RecipeListAdapter mAdapter;
private RecipeDao recDao;
private LiveData<List<Recipe>> RecipeList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recyclerview);
final RecipeListAdapter adapter = new RecipeListAdapter(this);
recyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(MainActivity.this);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecipeViewModel = new ViewModelProvider(this).get(RecipeViewModel.class);
mRecipeViewModel.getAllRecipes().observe(this, new Observer<List<Recipe>>() {
#Override
public void onChanged(#Nullable final List<Recipe> recipes) {
// Update the cached copy of the words in the adapter.
adapter.setWords(recipes);
}
});
void onItemClick(int position) {
//Delete Below test to pass data through
Recipe recipe = new Recipe("Test", "Yeet", "Jim");
// showAlertDialogBox();
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("Edit or Delete...");
alertDialog.setPositiveButton("Edit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
Intent update = new Intent(MainActivity.this, UpdateRecipeActivity.class);
update.putExtra("Name", recipe.getName());
update.putExtra("Ingredients", recipe.getIngredients());
update.putExtra("Method", recipe.getMethod());
startActivity(update);
}
});
alertDialog.setNegativeButton("Delete", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//Delete
}
});
alertDialog.show();
}
Here is the Recipe.class if you needed it!
#Entity(tableName = "recipe_table")
public class Recipe {
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name= "recipeId")
private int RecipeId;
private String name;
private String Ingredients;
private String Method;
#Ignore
public Recipe(String name, String Ingredients, String Method) {
this.RecipeId = RecipeId;
this.name = name;
this.Ingredients = Ingredients;
this.Method = Method;
}
public Recipe(String name) {
this.name = name;
}
public void changeText1(String text){
name = text;
}
//Add Image somehow!
public int getRecipeId() {
return RecipeId;
}
public void setRecipeId(int recipeId) {
RecipeId = recipeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMethod() {
return Method;
}
public void setMethod(String method) {
Method = method;
}
public String getIngredients() {
return Ingredients;
}
public void setIngredients(String ingredients) {
Ingredients = ingredients;
}
}
If you need anymore files, these are the files I have:
- RecipeListAdapter
- RecipeDao
- RecipeRepository
- RecipeRoomDatabase
- RecipeViewModel
Recipe Adapter code
public class RecipeListAdapter extends RecyclerView.Adapter {
private OnItemClickListener mListener;
private List recipeList;
public interface OnItemClickListener{
void onItemClick(int position, Recipe recipe);
}
public void setOnItemClickListener(OnItemClickListener listener){
mListener = listener;
}
class RecipeViewHolder extends RecyclerView.ViewHolder {
private final TextView recipeItemView;
private RecipeViewHolder(View itemView) {
super(itemView);
recipeItemView = itemView.findViewById(R.id.textView);
itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
if (mListener != null){
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION){
mListener.onItemClick(position,
recipeList.get(getAdapterPosition()));
}
}
}
});
}
}
private final LayoutInflater mInflater;
private List<Recipe> mRecipes; // Cached copy of words
RecipeListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
this.recipeList = recipeList;
}
#Override
public RecipeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.recyclerview_item, parent,
false);
return new RecipeViewHolder(itemView);
}
#Override
public void onBindViewHolder(RecipeViewHolder holder, int position) {
if (mRecipes != null) {
Recipe current = mRecipes.get(position);
holder.recipeItemView.setText(current.getName());
} else {
// Covers the case of data not being ready yet.
holder.recipeItemView.setText("No Recipes");
}
}
void setWords(List<Recipe> recipes){
mRecipes = recipes;
notifyDataSetChanged();
}
// getItemCount() is called many times, and when it is first called,
// mWords has not been updated (means initially, it's null, and we can't
return null).
#Override
public int getItemCount() {
if (mRecipes != null)
return mRecipes.size();
else return 0;
}
public interface OnNoteListener{}
}
Inside the onItemClick there is one more parameter need to add.
void onItemClick(int position, Recipe recipe) {
//Delete selected recipe from recipe list
arrayList.remove(recipe)
}
The onItemClick method will get called from adapter, from there you have to pass the selected receipe. In the adapter you have to use recipeList.get(getAdapterPosition()) to get the clicked receipe and pass this to the interface method, onItemClick along with the position.
So your code will look like this way inside the adapter,
itemClickListener.onItemClick(position,
recipeList.get(getAdapterPosition()))
Just as a note, please ensure instead of List, you need to take ArrayList to perform remove operation.

how to use Architecture Components ViewModel inside RecyclerView Adapter?

I have multiple ViewHolders that work as separated views inside a vertical RecyclerView. I'm practicing with the new Architecture Components ViewModel.
Inside my ViewModel I have a couple of MutableLiveData lists that i want to observe, but how can I call
ViewModelProviders.of((AppCompatActivity)getActivity()).get(FilterViewModel.class)
and
mFilterViewModel.getCountries().observe(this, new Observer<ArrayList<TagModel>>() {
#Override
public void onChanged(#Nullable ArrayList<TagModel> tagModels) {
}
});
without leaking the activity or save the activity inside the adapter?
my ViewModel
public class FilterViewModel extends ViewModel {
private final MutableLiveData<ArrayList<TagModel>> mCountries;
private final MutableLiveData<ArrayList<TagModel>> mSelectedCountryProvinceList;
private final MutableLiveData<ArrayList<TagModel>> mDistanceList;
public FilterViewModel(){
mCountries = new MutableLiveData<>();
mSelectedCountryProvinceList = new MutableLiveData<>();
mDistanceList = new MutableLiveData<>();
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mCountries.setValue(object.getCountries());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 5){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(5,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 6){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(6,"parent");
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mDistanceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == 51){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(51,"parent");
}
public void selectCountry(final TagModel country){
TagStore.getInstance().subscribe(new StoreObserver<TagSearchList>() {
#Override
public void update(TagSearchList object) {
mSelectedCountryProvinceList.setValue(object.toList());
}
#Override
public void update(int id, TagSearchList object) {
if (id == country.getId()){
TagStore.getInstance().unSubcribe(this);
update(object);
}
}
#Override
public void error(String error) {
}
}).get(country.getId(),"parent");
}
public LiveData<ArrayList<TagModel>> getCountries(){
return mCountries;
}
public LiveData<ArrayList<TagModel>> getDistances(){
return mDistanceList;
}
public LiveData<ArrayList<TagModel>> getProvinces(){
return mSelectedCountryProvinceList;
}
I am using Room Persistence library. Below is my code for recyclerview adapter using MVVM.
You can see CartViewModel and I have initialized it into the constructor. The constructor gets the context from the activity, and I have cast it into FragmentActivity.
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
Here is my full adapter class. I hope it will help.
public class CartListAdapter extends RecyclerView.Adapter<CartListAdapter.CartListViewHolder> {
private static final String TAG = "CartListAdapter";
private Context context;
private List<CartModel> cartModels;
private Double totalQuantity = 0.0;
private CartViewModel cartViewModel;
public CartListAdapter(Context context, List<CartModel> cartModels) {
this.context = context;
this.cartModels = cartModels;
cartViewModel = ViewModelProviders.of((FragmentActivity) context).get(CartViewModel.class);
}
#NonNull
#Override
public CartListViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new CartListViewHolder(LayoutInflater.from(context).inflate(R.layout.list_all_cart_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull CartListViewHolder holder, int position) {
CartModel cartModel = cartModels.get(position);
Glide.with(context)
.load(cartModel.getPPICLocate())
.into(holder.cartItemImage);
holder.tvCartProductName.setText(cartModel.getProductName());
holder.tvCartProductCategory.setText(cartModel.getPCategorySubID());
holder.tvCartProductPrice.setText(cartModel.getPPriceSales());
holder.etCartProductQuantity.setText(cartModel.getPQuantity());
holder.btnCartPQtIncrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity+1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
holder.btnCartPQtDecrease.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
totalQuantity = Double.valueOf(holder.etCartProductQuantity.getText().toString());
totalQuantity = totalQuantity-1;
cartModel.setPQuantity(totalQuantity.toString());
updateCart(cartModel);
}
});
}
#Override
public int getItemCount() {
return cartModels.size();
}
public class CartListViewHolder extends RecyclerView.ViewHolder{
private ImageView cartItemImage;
private TextView tvCartProductName,tvCartProductCategory,tvCartProductPrice,
etCartProductQuantity,tvCartProductPrevPrice;
private ImageButton btnCartPQtIncrease,btnCartPQtDecrease;
public CartListViewHolder(#NonNull View itemView) {
super(itemView);
cartItemImage= itemView.findViewById(R.id.cartItemImage);
tvCartProductName= itemView.findViewById(R.id.tvCartProductName);
tvCartProductCategory= itemView.findViewById(R.id.tvCartProductCategory);
tvCartProductPrice= itemView.findViewById(R.id.tvCartProductPrice);
etCartProductQuantity= itemView.findViewById(R.id.etCartProductQuantity);
tvCartProductPrevPrice= itemView.findViewById(R.id.tvCartProductPrevPrice);
btnCartPQtIncrease= itemView.findViewById(R.id.btnCartPQtIncrease);
btnCartPQtDecrease= itemView.findViewById(R.id.btnCartPQtDecrease);
}
}
public void addItems(List<CartModel> cartModels) {
this.cartModels = cartModels;
notifyDataSetChanged();
}
private void updateCart(CartModel cartModel){
String tqt = String.valueOf(cartModel.getPQuantity());
Log.d(TAG, "updateQuantity: "+tqt);
/*cartRepository.updateCartRepo(cartModel);*/
cartViewModel.updateCartItemVM(cartModel);
}
}
You could create an OnClickListener interface instead, then implement the onClick method (defined in your interface) in your fragment or activity where you have access to your view model.
My solution to this issue is;
create a new variable(ViewModel) for the layout (fragment or activity layout)
in your activity or fragment get the instance of your viewModel with ViewModelProviders
hold the data which fills your recyclerView in MutableLiveData and observe it and fill the adapter of recyclerView with the value you observed
here you mut be careful not to create adapter instance in observe method.
if you create it in observe method, it will make leaks

How to save and restore RecyclerView Items's positions using Json

I have a RecyclerView with 5 items and drag & drop feature. I want to save items's positions into SharedPreferences in order to restore them when the App is launched. Currently I'm able to save their positions into SharedPreferences using Json but the App crashes when I restore positions. Any solution? Thanks.
public static AppCompatActivity mActivity;
public static SharedPreferences SP;
public static SharedPreferences.Editor mEditor;
public static RecyclerView mRecyclerView;
public static RecyclerViewDragDropManager mRecyclerViewDragDropManager;
public static List<Long> mSaveItemsOrder;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mActivity = this;
SP = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
mEditor = SP.edit();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerViewDragDropManager = new RecyclerViewDragDropManager();
mRecyclerViewDragDropManager.setInitiateOnMove(false);
mRecyclerViewDragDropManager.setInitiateOnLongPress(true);
mRecyclerViewDragDropManager.setLongPressTimeout(300);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mRecyclerViewDragDropManager.createWrappedAdapter(new Adapter()));
mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView);
}
public static class Item {
public final long id;
public final String text;
public Item(long id, String text) {
this.id = id;
this.text = text;
}
}
public static class ViewHolder extends AbstractDraggableItemViewHolder {
Button mButton;
public ViewHolder(View itemView) {
super(itemView);
mButton = (Button) itemView.findViewById(R.id.button);
}
}
public static class Adapter extends RecyclerView.Adapter<ViewHolder> implements DraggableItemAdapter<ViewHolder> {
List<Item> mItems;
public Adapter() {
setHasStableIds(true);
mItems = new ArrayList<>();
if (SP.getString("items_order", null) == null) {
for (int mInt = 0; mInt < 5; mInt++) {
mItems.add(new Item(mInt, "Item " + mInt));
}
} else {
mItems = new Gson().fromJson(SP.getString("items_order", null), new TypeToken<Item>(){}.getType());
}
}
#Override
public long getItemId(int position) {
return mItems.get(position).id;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view, parent, false);
return new ViewHolder(mView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Item mItem = mItems.get(position);
holder.mButton.setText(mItem.text);
}
#Override
public int getItemCount() {
return mItems.size();
}
#Override
public void onMoveItem(int fromPosition, int toPosition) {
Item mMovedItem = mItems.remove(fromPosition);
mItems.add(toPosition, mMovedItem);
notifyItemMoved(fromPosition, toPosition);
}
#Override
public boolean onCheckCanStartDrag(ViewHolder holder, int position, int x, int y) {
return true;
}
#Override
public ItemDraggableRange onGetItemDraggableRange(ViewHolder holder, int position) {
return null;
}
#Override
public boolean onCheckCanDrop(int draggingPosition, int dropPosition) {
return true;
}
}
#Override
protected void onPause() {
super.onPause();
mSaveItemsOrder = new ArrayList<>();
for (int mInt = 0; mInt < mRecyclerView.getAdapter().getItemCount(); mInt++) {
mSaveItemsOrder.add(mRecyclerView.getAdapter().getItemId(mInt));
}
mEditor.putString("items_order", new Gson().toJson(mSaveItemsOrder)).commit();
}
This is the error:
https://www.dropbox.com/s/j2tf4n08depyynt/Error.txt?dl=0
The problem is with your JSON.
You the object you are serializing to JSON is mSaveItemsOrder which is an ArrayList. But on deserializing you give GSON the Class new TypeToken<Item>(){}.getType().
So you store an ArrayList in your JSON but trying to deserialzie a different Class, that won't work.
This should work:
mItems = new Gson().fromJson(SP.getString("items_order", null), new TypeToken<ArrayList>(){}.getType(););

Categories