public class AdapterQuestion extends RecyclerView.Adapter<AdapterQuestion.ViewQuestion>{
private LayoutInflater mLayoutInflater;
//this is an arrayList of questionData objects
private ArrayList<QuestionData> data =new ArrayList<>();
//Created the layoutInflator
public AdapterQuestion(Context context){
//get from context
mLayoutInflater=LayoutInflater.from(context);
}
public void setBloglist(ArrayList<QuestionData> data){
this.data =data;
notifyItemRangeChanged(0, data.size());
System.out.print("Size of the array "+data.size());
}
#Override
public ViewQuestion onCreateViewHolder(ViewGroup parent, int viewType) {
//inflates the customQuestion view or converts it to java code
View view= mLayoutInflater.inflate(R.layout.customquestion, null);
//We now want to convert the View into a ViewQuestion, view Question takes
//a view so we pass the view into view question and then return it.
ViewQuestion holder=new ViewQuestion(view);
return holder;
}
//ViewGroup parent and ViewType are not being assigned.
#Override
public void onBindViewHolder(ViewQuestion holder, int position) {
//here we need to bind the data to our view, there is currently no Data!
//We need to get the data from our JSON
//Parameters is a ViewHolder and a Position
QuestionData currentBlog= data.get(position);
holder.answerText.setText(currentBlog.getMtext());
holder.answerId.setText(currentBlog.getId());
holder.mVotes.setText(currentBlog.getVotes());
holder.mLikeButton.setTag(currentBlog);
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewQuestion extends RecyclerView.ViewHolder{
//once we create it once the reclycer view will automatically recycle it
private TextView answerText;
private TextView answerId;
private TextView mVotes;
private LikeButton mLikeButton;
public ViewQuestion (View itemView){
super(itemView);
//here we are finding the views by their ID
answerText=(TextView)itemView.findViewById(R.id.answerText);
answerId=(TextView)itemView.findViewById(R.id.answerId);
mVotes=(TextView)itemView.findViewById(R.id.VoteTextView);
mLikeButton=(LikeButton)itemView.findViewById(R.id.heart_buttons);
mLikeButton.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
Voting vote = new Voting();
vote.onUpVote(convertToString(),getAdapterPosition(),ViewQuestion.this);
System.out.print("Adapter Position"+getAdapterPosition());
}
#Override
public void unLiked(LikeButton likeButton) {
Voting onDown=new Voting();
onDown.onDownVote(convertToString(), getAdapterPosition(), ViewQuestion.this);
}
});
}
public String getVoteView(){
String voteView=mVotes.getText().toString();
return voteView;
}
public String convertToString(){
String converted=answerId.getText().toString();
return converted;
}
public int convertToInt(){
String converted=answerId.getText().toString();
int ConvertedInt=Integer.parseInt(converted);
return ConvertedInt;
}
}
}
1.First off, why do we extend RecyclerView.Adapter as an arrayList?
2.public void setBloglist(ArrayList<QuestionData> data){
this.data =data;
notifyItemRangeChanged(0, data.size());
System.out.print("Size of the array "+data.size());
}
In the method above, we passed in an ArrayList, and we set the data of the Arraylist to the data passed in but dont we have to set the data in the ViewHolder?
3. super(itemView); Why does the ViewHolder extend super? isnt that itself?
It is not ArrayList it is generics
this keyword refers to the current object so we are setting the value of the data
instance variable in the AdapterQuestion's object to the value passed as method arguement
the ViewHolder does'nt extend a class named super but your ViewQuestion class extends RecyclerView.ViewHolder class ,the super(itemView);is used to call the RecyclerView.ViewHolder constructor
Related
I want to pass data from recyclerview to another both in fragment, first adapter
for display item, and second adapter for basket fragment that want to put selected item in.
Adapter I want to take data from:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(ArrayList<FruitItem> fruitItems, Context context) {
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
public FruitItemAdapter() {
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
final FruitItem data_position = fruitItems.get(position);
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public static class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_price, fruit_name;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_price = itemView.findViewById(R.id.fruit_price);
fruit_name = itemView.findViewById(R.id.fruit_name)
}
}
}
this is adapter for basket fragment that I want to put the data in
public class Basket_Adapter extends RecyclerView.Adapter<Basket_Adapter.viewHolder> {
private Context context;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
public Basket_Adapter(Context context, ArrayList<FruitItem> fruitItems) {
this.context = context;
this.fruitItems = fruitItems;
notifyDataSetChanged();
}
public Basket_Adapter(){
}
#NonNull
#Override
public Basket_Adapter.viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int
viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.fruits_item,parent,false);
viewHolder viewHolder = new viewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull Basket_Adapter.viewHolder holder, int position) {
holder.fruit_img.setImageResource(fruitItems.get(position).getFruit_img());
holder.fruit_name.setText(fruitItems.get(position).getFruit_name());
holder.fruit_price.setText(fruitItems.get(position).getFruit_price());
}
#Override
public int getItemCount() {
return fruitItems.size();
}
public void setfruitItem(ArrayList<FruitItem> fruitItems) {
this.fruitItems = fruitItems;
}
public class viewHolder extends RecyclerView.ViewHolder {
private ImageView fruit_img;
private TextView fruit_name;
private TextView fruit_price;
public viewHolder(#NonNull View itemView) {
super(itemView);
fruit_img = itemView.findViewById(R.id.fruit_img);
fruit_name = itemView.findViewById(R.id.fruit_name);
fruit_price = itemView.findViewById(R.id.fruit_price);
}
}
Now, what I can use to pass data between them.
You can achieve this by using the delegation pattern. Basically you create an interface relative to the first adapter (you can put it inside the adapter class or outside depending on your coding style) and you require it as an argument inside the adapter constructor like this:
public class FruitItemAdapter extends RecyclerView.Adapter<FruitItemAdapter.viewHolder> {
private Delegate delegate;
ArrayList<FruitItem> fruitItems = new ArrayList<>();
private Context context;
public FruitItemAdapter(Delegate delegate, ArrayList<FruitItem> fruitItems, Context context) {
this.delegate = delegate;
this.fruitItems = fruitItems;
this.context = context;
notifyDataSetChanged();
}
...
interface Delegate {
public void passItem(FruitItem item);
}
}
As you can see the interface has the method you need, but there's no implementation yet.
In this class you can just pretend that your delegate works and do the magic for you, for example by setting a click listener on the root view of your item in onBindViewHolder that will call delegate.passItem(fruitItems.get(position)) on each click.
Let's move on to the fragment.
Here is the key part. The fragment must implement the interface we just created by overriding its methods. Like so:
class ExampleFragment extends Fragment implements FruitItemAdapter.Delegate {
...
#Override
public void passItem(FruitItem item) {
// here you pass the item in a list inside
// the shared preferences.
}
}
For your case the best way is to store your items in a database or in the shared preferences. We go with the shared preferences because is simpler, but keep in mind that shared preferences have limited memory capacity and you should use a database like Room instead.
Inside the override method you pass your item to a list stored in the shared preferences. Since your item is not a primitive object i suggest you to look at this answer that show how to store complex object as a string:
https://stackoverflow.com/a/18463758/18740763.
In your case the object that needs to be serialized is an Array or a List of objects.
Every time you need to put a new object in the list you need to follow these steps:
get the list from shared preferences
deserialize it
add the new item
serialize it again
put it back in the shared preferences under the same key
If you stored your items correctly now you should be able to access the shared list in every fragment or activity of your application. So simply access your list from the fragment that implements the second adapter, deserialize it, just addAll() the items the the adapter list and notifyDataSetChanged().
I have tab layout (3 fragments) with recyclerview and checkboxes for every fragment. I set up onClickListener, but after I exit my app, checkbox statuses are reseted. I tried some solutions I found online some solutions (about shared preferences) but neither work for me. Maybe I implement it wrong. Can you help me ?
Also if need, I can share with you my Fragment file.
recyclerview java:
public class RecyclerViewAdapter extends RecyclerView.Adapter <RecyclerViewAdapter.MyViewHolder>{
Context mContext;
List<RecTab1> mData;
public RecyclerViewAdapter(Context mContext, List<RecTab1> mData) {
this.mContext = mContext;
this.mData = mData;
}
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v ;
v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1,parent,false);
MyViewHolder vHolder = new MyViewHolder(v);
return vHolder;
}
#Override
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
holder.tv_name.setText(mData.get(position).getName());
holder.tv_subName.setText(mData.get(position).getSubName());
holder.cb_checkbox.setChecked(mData.get(position).getSelected());
holder.cb_checkbox.setTag(position);
holder.cb_checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Integer pos = (Integer) holder.cb_checkbox.getTag();
Toast.makeText(mContext, mData.get(pos).getName() + " clicked!", Toast.LENGTH_LONG).show();
if (mData.get(pos).getSelected()) {
mData.get(pos).setSelected(false);
} else {
mData.get(pos).setSelected(true);
}
}
});
}
#Override
public int getItemCount() {
return mData.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder{
private TextView tv_name;
private TextView tv_subName;
private CheckBox cb_checkbox;
public MyViewHolder (View itemView){
super (itemView);
tv_name = (TextView) itemView.findViewById(R.id.Item1Name);
tv_subName = (TextView) itemView.findViewById(R.id.Item1SubName);
cb_checkbox = (CheckBox) itemView.findViewById(R.id.CheckboxID);
}
}
}
item java:
public class RecTab1 {
private String Name;
private String SubName;
private boolean isSelected;
public RecTab1(){
}
public RecTab1 (String name, String subName){
Name = name;
SubName = subName;
}
public String getName() {
return Name;
}
public String getSubName() {
return SubName;
}
public void setName(String name) {
Name = name;
}
public void setSubName(String subName) {
SubName = subName;
}
public boolean getSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
}
There are basically 2 kinds of persistence:
Temporary persistence (Scope: can be only used inside Activity/Fragment)
Long-term persistence (Scope: goes beyond the lifecycle of Activity/Fragment)
I think, you implemented first technique by creating Rect1 object somewhere(I assumed you did not save them in the database as I did not see those lines of code) and later trying to access the values when needed elsewhere. But, those variables will be destroyed and recreated later on destroying and recreating of the fragment when you would switch between tabs in your TabLayout.
What you need is the second one.
There are many versions of this kind of persistence as :
- SharedPreferences
- Sqlite Database
- Online Database such as Firebase
For eg: In your case, if you have few numbers of tabs which again has few numbers of information to persist then, you can use SharedPreferences. If there is larger number of tabs and in turn larger number of information to persist then, using Sqlite Database is better. See this link about using Room to save data in Sqlite
Now using SharedPreferences, you can save the checked state of the CheckBox into the preference file in the onCheckChangedListener method as:
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1, parent, false);
Checkbox cb_checkbox = v.findViewById(R.id.CheckboxID);
cb_checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", Context.MODE_PRIVATE)
.edit()
.putBoolean("cb_checkbox", isChecked)
.apply();
}
});
I set the onCheckChangedListener in the onCreateViewHolder because mContext was available. You could have also done in inside the MyViewHolder class passing the Context object in the constructor of MyViewHolder.It is NOT recommended to set listener in onBindViewHolder() because it is called multiple times during binding so, there would be recurrent setting of listener even for those cb_checkbox in the MyViewHolder object whose listeners are already set.
Now, to retrieve the checked state of the cb_checkbox, we will see in our SharedPreferences to find information if it is saved previously as :
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
// your other binding code
// code for binding previous state of the checkbox if is saved otherwise false as a default
boolean checkedState = mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", MODE_PRIVATE)
.getBoolean("cb_checkbox", false);
holder.cb_checkbox.setChecked(checkedState);
}
I have multiple array lists inside an arraylist :
[[Object1, Object2],[Object3, Object4],[Object5, Object6]]
I display the first array list in a recyclerview that displays one arraylist at a time:
myViewHolder.bindTo(cities.get(0).get(i));
I want to click a button in another class that would show change the array list shown. How would I achieve this?
Recycler View Adapter Class:
private List<List<Country>> cities;
#NonNull
#Override
public MyViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
PlannerItemBinding plannerItemBinding =
DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.planner_item, viewGroup, false);
return new MyViewHolder(plannerItemBinding);
}
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.bindTo(cities.get(0).get(i));
}
#Override
public int getItemCount() {
if (cities != null) {
return cities.size();
} else {
return 0;
}
}
public void setCityList(List<List<Country>> cities) {
this.cities = cities;
notifyDataSetChanged();
}
class MyViewHolder extends RecyclerView.ViewHolder {
private PlannerItemBinding plannerItemBinding;
public MyViewHolder(#NonNull PlannerItemBinding plannerItemBinding) {
super(plannerItemBinding.getRoot());
this.plannerItemBinding = plannerItemBinding;
}
void bindTo(Country country) {
plannerItemBinding.setVariable(com.example.planner.BR.city, country);
plannerItemBinding.setVariable(com.example.planner.BR.adapterPosition, getLayoutPosition());
plannerItemBinding.setVariable(com.example.planner.BR.countryImageMedium, country.getImages().get(0).getSizes().getMedium());
plannerItemBinding.executePendingBindings();
}
}
}
Set a setter in your RecyclerView.Adapter:
public updateCities(List<List<Coutry>> cities) {
this.cities = cities;
notifydatasetchanged();
}
so that you can call it in onClick() of that button with the new data.
This will update the model of your adapter with the passed data and notify the recyclerview that its data has changed.
You create an onClickListener on the object of your choice, and then when it is clicked you just setCityList to the new data and use notifydatasetchanged on your adapter
As I'm new to android, I'm struggling to highlight Recyclerview clicked or current item. I have tried some workarounds but nothing helps. Basically I want to highlight selected item even after it is coming back from respective Fragment. Please check my code and help me to get done. Thanks.
public class ContentaAdapter extends RecyclerView.Adapter<ContentaAdapter.MyViewHolder> {
Context context;
ArrayList<String> ItemTitle;
ArrayList<String> ItemSource;
public ContentaAdapter(Context context, ArrayList<String> ItemTitle, ArrayList<String> ItemSource) {
this.context = context;
this.ItemTitle = ItemTitle;
this.ItemSource = ItemSource;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.home_items_layout, parent, false);
MyViewHolder vh = new MyViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.ItemTitle.setText(ItemTitle.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment contentdisplay = new ViewContentFragment();
Bundle bundle=new Bundle();
bundle.putStringArrayList("ItemTitle",ItemTitle);
bundle.putStringArrayList("ItemSource",ItemSource);
bundle.putInt("position",position);
bundle.putInt("ItemCounts",ItemTitle.size());
contentdisplay.setArguments(bundle);
((MainActivity)context).replaceFragment(contentdisplay);
}
});
}
#Override
public int getItemCount() {
return ItemTitle.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView ItemTitle;
public MyViewHolder(View itemView) {
super(itemView);
ItemTitle = (TextView) itemView.findViewById(R.id.item_title);
}
}
}
you need to to add isSelected state in to your list item data model and change it onClick.
And when you know state you can change background in ViewHolder
if (isSelected) {
// set selected background here
} else {
// set not selected background here
}
And instead of keeping two lists in adapter you should create one with model ArrayList<DataModel> similar to this:
class DataModel {
String ItemTitle;
String ItemSource;
Boolean isSelected;
}
also you shouldn't pass both list to other fragment, instead take only what you need, for example yourList.get(position);
In my application should be a lot of adapters similar to each other and I would like to know whether it is possible to make the interface or superclass to inherit from there and then, instead of writing 10 adapters, thanks !!
My adapter code
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsViewHolder> {
private List<News> newsList;
private Context ctx;
public NewsAdapter(List<News> newsList, Context ctx) {
this.newsList = newsList;
this.ctx = ctx;
}
static class NewsViewHolder extends RecyclerView.ViewHolder {
CardView cv;
TextView newsTitle;
TextView newsDescription;
ImageView newsImage;
TextView newsDate;
NewsViewHolder(View itemView) {
super(itemView);
cv = (CardView) itemView.findViewById(R.id.cvNews);
newsTitle = (TextView) itemView.findViewById(R.id.title_news);
newsDescription = (TextView) itemView.findViewById(R.id.description_news);
newsDate = (TextView) itemView.findViewById(R.id.date_news);
newsImage = (ImageView) itemView.findViewById(R.id.image_news);
}
}
#Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent,
false);
return new NewsViewHolder(v);
}
#Override
public void onBindViewHolder(NewsViewHolder holder, int position) {
holder.newsTitle.setText(newsList.get(position).newsTitle);
holder.newsDescription.setText(newsList.get(position).newsDescription);
holder.newsDate.setText(newsList.get(position).newsDate);
Glide.with(ctx).load(Constants.SITE + newsList.get(position).newsImage)
.into(holder.newsImage);
}
#Override
public int getItemCount() {
return newsList.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
}
All should reflect like this
it is possible to make the interface or superclass to inherit from
there and then, instead of writing 10 adapters
It is possible, but of course there must be something in common. For a start the dataset should be homogeneous. E.g. your items should all implement an interface, a contract between the item and the adapter itself. In your case, it could be
public interface DataItem {
String getTitle();
String getDescription();
String getDate();
String getImageUrl();
}
and instead of a private List<News> newsList;, you will have private List<? extends DataItem> newsList;. As I said, all your items have to implement that interface, and the properties have to be accessed through the getters