RecyclerView - a single selection selects every 10 row - android

It's strange but when I long click on one row using my code, the star on that row turns gold (which is what I want), but also each star ten rows apart.
This is my code:
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView localeDisplay;
private static final int grey_blue = 0xff546E7A;
private static final int gold = 0xffffa000;
public MyViewHolder(final View view) {
super(view);
localeDisplay = (TextView) view.findViewById(R.id.languageText);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Languages currentLanguages = languagesList.get(getAdapterPosition());
Snackbar snackbar;
snackbar = Snackbar.make(view, currentLanguages.getLocaleDisplay() + " selected", Snackbar.LENGTH_INDEFINITE)
.setAction("Next", new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), MainActivity.class);
v.getContext().startActivity(intent);
}
});
View snackBarView = snackbar.getView();
snackBarView.setBackgroundColor(grey_blue);
snackbar.show();
}
}
);
view.setOnLongClickListener(new View.OnLongClickListener()
{
#Override
public boolean onLongClick(View v) {
Toast.makeText(v.getContext(), "Position is " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
ImageView star = (ImageView) view.findViewById(R.id.imageView);
if (star.getColorFilter() == null) {
star.setColorFilter(gold);
} else star.clearColorFilter();
return true;
}
}
);
}
I have tried following this tutorial but the same behavior happens.
Any ideas what I could do to correct this?

in your adapter constructor, just add this part:
setHasStableIds(true).
and after that override the following methods in the adapter class.
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}

Seems like your view is being recycled, what means your listener reference is being called to all recycled views.
An easy way to solve this is setting new references for each single view at onBindViewHolder method. Usually Viewholder is used to find views and keep the references for recycled views, isn't a good idea set data inside it.
You could change the viewholder for:
public ExampleViewHolder(View view) {
super(view);
myContainer = (LinearLayout) view.findViewById(R.id.myContainer);
localeDisplay = (TextView) view.findViewById(R.id.languageText);
star = (ImageView) view.findViewById(R.id.imageView);
}
And set the listener at onBindViewHolder:
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
ExampleHolder holder = (ExampleHolder) viewHolder;
//Insert the position reference
holder.myContainer.setTag(position);
// Setting listeners
holder.myContainer.setOnClickListener(this);
holder.myContainer.setOnLongClickListener(this);
}
Then implement the OnLongClickListener and OnClickListener at your adapter.
#Override
public boolean onLongClick(View v) {
//Getting position
int position = (int)v.getTag();
//Insert your code
return false;
}
#Override
public void onClick(View v) {
//code here
}
Drop me a line back if works. Good luck.

This is because you are getting all items that have the R.id.imageView id. To do what you want, you need to grab the item that was clicked and change the color of the selected line only;

Related

Get selected item position of RecyclerView

I am trying to get position of the clicked item in RecyclerView. In adapter class, I am trying to create intent and send clicked item's contents. Also I created popup menu for two option. It is in adapter class too. onBindViewHolder position is works for puting contents in the rows of RecyclerView. However I couldn't reach that position from outside of method.
This is adapter class.
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements PopupMenu.OnMenuItemClickListener {
public ArrayList<MovieModel.Results> resultList;
public Context context;
public RecyclerViewAdapter(ArrayList<MovieModel.Results> list, Context context) {
this.resultList = list;
this.context = context;
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView posterImage;
ImageView addIcon;
TextView movieName;
TextView date;
TextView overview;
public ViewHolder(#NonNull View itemView) {
super(itemView);
posterImage = itemView.findViewById(R.id.movie_poster);
addIcon = itemView.findViewById(R.id.addImage);
movieName = itemView.findViewById(R.id.movieNameText);
date = itemView.findViewById(R.id.dateText);
overview = itemView.findViewById(R.id.overviewText);
}
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_list_2, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (position < getItemCount()) {
String title = resultList.get(position).getTitle();
String date = resultList.get(position).getRelease_date();
String overview = resultList.get(position).getOverview();
String posterPath = resultList.get(position).getPoster_path();
holder.movieName.setText(title);
holder.date.setText(date);
holder.overview.setText(overview);
if (posterPath == null) {
holder.posterImage.setImageDrawable(context.getDrawable(R.drawable.no_poster));
} else {
Glide.with(context).load(FeedActivity.BASE_PHOTO_URL + posterPath).into(holder.posterImage);
}
int finalPosition = position;
holder.addIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(context, "You clicked : " + finalPosition, Toast.LENGTH_SHORT).show();
showPopup(v);
}
});
}
position++;
}
private void showPopup(View v) {
PopupMenu popup = new PopupMenu(context,v);
popup.setOnMenuItemClickListener(this);
MenuInflater inflater = popup.getMenuInflater();
inflater.inflate(R.menu.menu, popup.getMenu());
popup.show();
}
#Override
public boolean onMenuItemClick(MenuItem item) {
// Here I need to position of clicked item in Recyclerview, and I will get title, date etc.
int pos;
if(item.getItemId() == R.id.menuAdd){
// Find here to get position of clicked movie.
String title = resultList.get(pos).getTitle();
String date = resultList.get(pos).getRelease_date();
String overview = resultList.get(pos).getOverview();
String posterpath = resultList.get(pos).getPoster_path();
Intent intent1 = new Intent(context,ListActivity.class);
intent1.putExtra("title",title);
intent1.putExtra("date",date);
intent1.putExtra("overview",overview);
intent1.putExtra("posterpath",posterpath);
context.startActivity(intent1);
return true;
}
else if(item.getItemId() == R.id.menuShowDetails){
int movieId = resultList.get(pos).getMovieId();
Intent intent1 = new Intent(context, MovieDetails.class);
intent1.putExtra("movie_id",movieId);
context.startActivity(intent1);
return true;
}
return false;
}
#Override
public int getItemCount() {
return resultList.size();
}
}
You can use the ViewHolder's getAdapterPosition() to retrieve the item's position within an interface method. Then store the clicked position in a member variable.
Additionally, there shouldn't be a need to call position++ from within your onBindViewHolder.
// Create a member variable to store the clicked position
public int clickedPos = -1;
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// ...
holder.addIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// When you're inside the click listener interface,
// you can access the position using the ViewHolder.
// We'll store the position in the member variable in this case.
clickedPos = holder.getAdapterPosition();
}
});
// Remove the 'position++' call as the position should already be handled without explicitly updating it.
}
#Override
public boolean onMenuItemClick(MenuItem item) {
// You can use clickedPos here to perform whatever tasks you need.
// ...
}

Checkbox changing state when scrolling in recyclerview

I made a small app that shows me a list of all the apps installed to my phone I want to add a check box to every cardview so that I can mark my favorite apps and other classification. The problem is when scrolling through the list the state of the checkbox change ex. I checked chrome and when I scrolled down then scrolled up chrome is not marked and a random app is checked. I searched for other question related to this problem but none of those solutions worked for me.
updated version of appsadapter.java
public class AppsAdapter extends RecyclerView.Adapter<AppsAdapter.ViewHolder>{
private final SparseBooleanArray array=new SparseBooleanArray();
public class ViewHolder extends RecyclerView.ViewHolder{
public CardView cardView;
public ImageView imageView;
public TextView textView_App_Name;
public CheckBox checkBox;
public ViewHolder (View view){
super(view);
checkBox = (CheckBox) view.findViewById(R.id.chckbox);
cardView = (CardView) view.findViewById(R.id.card_view);
imageView = (ImageView) view.findViewById(R.id.imageview);
textView_App_Name = (TextView) view.findViewById(R.id.Apk_Name);
//textView_App_Package_Name = (TextView) view.findViewById(R.id.Apk_Package_Name);
}
}
private Context context1;
private List<String> stringList;
public AppsAdapter(Context context, List<String> list){
context1 = context;
stringList = list;
}
//viewholder initialized
#Override
public AppsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View view2 = LayoutInflater.from(context1).inflate(R.layout.cardview_layout,parent,false);
ViewHolder viewHolder = new ViewHolder(view2);
return viewHolder;
}
//DATA IS BOUND TO VIEWS
private SparseBooleanArray sba = new SparseBooleanArray();
#Override
public void onBindViewHolder(ViewHolder viewHolder,final int position){
viewHolder.setIsRecyclable(false);
ApkInfoExtractor apkInfoExtractor = new ApkInfoExtractor(context1);
final String ApplicationPackageName = (String) stringList.get(position);
//calling apps name and icon
String ApplicationLabelName = apkInfoExtractor.GetAppName(ApplicationPackageName);
Drawable drawable = apkInfoExtractor.getAppIconByPackageName(ApplicationPackageName);
//setting app name and icon for every card
viewHolder.textView_App_Name.setText(ApplicationLabelName);
viewHolder.imageView.setImageDrawable(drawable);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sba.put(position, !sba.get(position));
notifyDataSetChanged();
}
});
viewHolder.checkBox.setChecked(sba.get(position));
/*Adding click listener on CardView to open clicked application directly from here
viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = context1.getPackageManager().getLaunchIntentForPackage(ApplicationPackageName);
if(intent != null){
context1.startActivity(intent);
}
else {
Toast.makeText(context1,ApplicationPackageName + " Error, Please Try Again.", Toast.LENGTH_LONG).show();
}
}
});*/
}
#Override
public int getItemCount(){
return stringList.size();
}
}
That is because in the recycler view, item views are re used to show new data. You have to add a variable in your data item that holds the state of the checkbox at a particular position. Then in the onBindViewHolder you can check the value of the tracking variable and set the state of the checkbox like yourCheckbox.setchecked(item.getSelected()) set the tracking variable value in the onCheckChanged method
set view onclicklistener in BindViewholder method so you can use the current position of item as in
private SparseBooleanArray sba = new SparseBooleanArray();
#Override
public void onBindViewHolder(ViewHolder viewHolder,final int position){
viewHolder.setIsRecyclable(false);
ApkInfoExtractor apkInfoExtractor = new ApkInfoExtractor(context1);
final String ApplicationPackageName = (String) stringList.get(position);
//calling apps name and icon
String ApplicationLabelName = apkInfoExtractor.GetAppName(ApplicationPackageName);
Drawable drawable = apkInfoExtractor.getAppIconByPackageName(ApplicationPackageName);
//setting app name and icon for every card
viewHolder.textView_App_Name.setText(ApplicationLabelName);
viewHolder.imageView.setImageDrawable(drawable);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sba.put(position,!sba.get(position));
notifyDataSetChanged();
}
});
viewHolder.checkBox.setChecked(sba.get(position));
}
Set checkbox inside checkBox onclickListener
holder.mCheckBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CheckBox checkBox = (CheckBox) view;
mDataModel = (DataModel) checkBox.getTag();
mDataModel.setChecked(checkBox.isChecked());
arrayList.get(position).setChecked(checkBox.isChecked());
}
});

How to use notifyDataSetChanged and setText inside a same onclick method

I need to use notifyDataSetChanged() and setText a value to a TextView inside onBindViewHolder. I tried to use both inside onClick method,
qtyIncrease.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
quantityText.setText("Good");
toatlPriceText.setText("250");
notifyDataSetChanged();
}
});
My adapter class,
public class CartCardviewAdapter extends RecyclerView.Adapter<CartCardviewAdapter.MyViewHolder> {
private Context context;
private ArrayList<CartCardviewModel> dataSet;
private ShoppingCart shoppingCart;
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView itemNameText, itemTypeText, itemDescText, unitPriceText, toatlPriceText, quantityText;
ImageView itemImage, removeIcon, qtyIncrease, qtyDecrease;
public MyViewHolder(final View itemView) {
super(itemView);
this.itemNameText = (TextView) itemView.findViewById(R.id.item_name_text);
this.itemTypeText = (TextView) itemView.findViewById(R.id.item_type_text);
this.itemDescText = (TextView) itemView.findViewById(R.id.item_desc_text);
this.unitPriceText = (TextView) itemView.findViewById(R.id.item_unit_price_text);
this.toatlPriceText = (TextView) itemView.findViewById(R.id.item_total_price_text);
this.quantityText = (TextView) itemView.findViewById(R.id.item_quantity_text);
this.itemImage = (ImageView) itemView.findViewById(R.id.item_image);
this.removeIcon = (ImageView) itemView.findViewById(R.id.item_remove_icon);
this.qtyIncrease = (ImageView) itemView.findViewById(R.id.cart_quantity_increase);
this.qtyDecrease = (ImageView) itemView.findViewById(R.id.cart_quantity_decrease);
}
}
public CartCardviewAdapter(ArrayList<CartCardviewModel> data) {
this.dataSet = data;
}
#Override
public CartCardviewAdapter.MyViewHolder onCreateViewHolder(final ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cart_cardview_layout, parent, false);
CartCardviewAdapter.MyViewHolder myViewHolder = new CartCardviewAdapter.MyViewHolder(view);
context = parent.getContext();
return myViewHolder;
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onBindViewHolder(final CartCardviewAdapter.MyViewHolder holder, final int listPosition) {
shoppingCart = MainActivity.getCartInstance().getCart();
TextView itemNameText = holder.itemNameText;
TextView itemTypeText = holder.itemTypeText;
TextView itemDescText = holder.itemDescText;
TextView unitPriceText = holder.unitPriceText;
final TextView toatlPriceText = holder.toatlPriceText;
final TextView quantityText = holder.quantityText;
ImageView itemImage = holder.itemImage;
ImageView removeIcon = holder.removeIcon;
ImageView qtyIncrease = holder.qtyIncrease;
ImageView qtyDecrease = holder.qtyDecrease;
itemNameText.setText(dataSet.get(listPosition).getItemName());
itemTypeText.setText(dataSet.get(listPosition).getItemType());
itemDescText.setText(dataSet.get(listPosition).getItemDescription());
unitPriceText.setText(String.valueOf(dataSet.get(listPosition).getUnitPrice()));
toatlPriceText.setText(String.valueOf(dataSet.get(listPosition).getTotalPrice()));
String qty;
if (dataSet.get(listPosition).getItemQuantity() < 9) {
qty = "0" + String.valueOf(dataSet.get(listPosition).getItemQuantity());
} else {
qty = String.valueOf(dataSet.get(listPosition).getItemQuantity());
}
quantityText.setText(qty);
Picasso.with(context).load(dataSet.get(listPosition).getItemImageUrl()).into(itemImage);
removeIcon.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(v.getContext(), String.valueOf(listPosition), Toast.LENGTH_SHORT).show();
shoppingCart.removeItem(listPosition);
dataSet.remove(listPosition);
notifyDataSetChanged();
}
});
qtyIncrease.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
shoppingCart.increaseItemQuantity(listPosition);
quantityText.setText(String.valueOf(shoppingCart.getItemQuantity(listPosition)));
toatlPriceText.setText(String.valueOf(shoppingCart.getTotalPrice(listPosition)));
notifyDataSetChanged();
}
});
qtyDecrease.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (shoppingCart.getItemQuantity(listPosition) == 1) {
Toast.makeText(v.getContext(), "Already Minimum Quantity is Reached", Toast.LENGTH_SHORT).show();
} else {
shoppingCart.decreaseItemQuantity(listPosition);
quantityText.setText(String.valueOf(shoppingCart.getItemQuantity(listPosition)));
toatlPriceText.setText(String.valueOf(shoppingCart.getTotalPrice(listPosition)));
notifyDataSetChanged();
}
}
});
}
#Override
public int getItemCount() {
return dataSet.size();
}
}
but both don't work at a click. I need to go back and come to see the affected change. I could't understand the problem. Please help me
First This line #RequiresApi(api = Build.VERSION_CODES.N) is for too restrictive, take into consideration lower levels down the line. There are many ways to approach this problem, first you can use a RecyclerView.OnItemTouchListener to the recycler hosting the adaptor. Here is a detailed tutorial describing single and long click , Link. Another approach is the interface segration principle.
In the adaptor class, create a interface, with one method
method signature (View view, int position), depicts a view clicked with repective position in adaptor.
Declare a instance of this interface in the adaptor
Modify the contructor to accept a interface of that type
Let the class with the recylcler view instance implement above interface
Pass a new instance to the contructor in the implemented class
Then in the overriden method, change your text and call adaptor.notifyItemChanged(position)
oh, also, in the adaptor class where the views gets init , set onClicklistener with the interface instance.
This tutorial describes exactly the above in great detail,link.
Your welcome!
the click won't trigger from there , you need to set the click listener of the Image View "qtyIncrease" inside the ViewHolder not in "OnBindViewHolder"
public static class MyViewHolder extends RecyclerView.ViewHolder {
TextView itemNameText, itemTypeText, itemDescText, unitPriceText, toatlPriceText, quantityText;
ImageView itemImage, removeIcon, qtyIncrease, qtyDecrease;
public MyViewHolder(final View itemView) {
super(itemView);
this.itemNameText = (TextView) itemView.findViewById(R.id.item_name_text);
this.itemTypeText = (TextView) itemView.findViewById(R.id.item_type_text);
this.itemDescText = (TextView) itemView.findViewById(R.id.item_desc_text);
this.unitPriceText = (TextView) itemView.findViewById(R.id.item_unit_price_text);
this.toatlPriceText = (TextView) itemView.findViewById(R.id.item_total_price_text);
this.quantityText = (TextView) itemView.findViewById(R.id.item_quantity_text);
this.itemImage = (ImageView) itemView.findViewById(R.id.item_image);
this.removeIcon = (ImageView) itemView.findViewById(R.id.item_remove_icon);
this.qtyIncrease = (ImageView) itemView.findViewById(R.id.cart_quantity_increase);
this.qtyDecrease = (ImageView) itemView.findViewById(R.id.cart_quantity_decrease);
qtyIncrease.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
quantityText.setText("Good");
toatlPriceText.setText("250");
notifyDataSetChanged();
}
});
}

Why RecyclerView Items appear in wrong positions?

I am using RecyclerView in my application to create a forum for the users.
But I have problem with position of item! sometimes items will show in wrong positions! and some times items sow twice and some items doesn't show!
I have diffrent views in my recyclerView and because of that I used of multiView in it.
This is my recyclerView Adapter that I am using:
public class chatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final ArrayList<ChatModel> chatArray = new ArrayList<>();
private Context mContext;
FragmentForum fragmentForum;
public chatAdapter(ArrayList<ChatModel> chatArray, Context mContext, FragmentForum fragmentForum) {
this.chatArray.addAll(chatArray);
this.mContext = mContext;
this.fragmentForum = fragmentForum;
}
public static class ViewHolderNoFile extends RecyclerView.ViewHolder {
ImageView reply;
TextView qText;
TextView aText;
TextView aUserName;
TextView qUserName;
LinearLayout layoutAnswer;
public ViewHolderNoFile(View v) {
super(v);
reply = (ImageView) v.findViewById(R.id.imgReplay);
qText = (TextView) v.findViewById(R.id.txt_question);
aText = (TextView) v.findViewById(R.id.txt_answer);
aUserName = (TextView) v.findViewById(R.id.txt_a_user_name);
qUserName = (TextView) v.findViewById(R.id.txt_q_user_name);
layoutAnswer = (LinearLayout) v.findViewById(R.id.answer_box_item);
}
}
public static class ViewHolderQFile extends RecyclerView.ViewHolder {
ImageView qImage;
ImageView reply;
TextView qText;
TextView aText;
TextView aUserName;
TextView qUserName;
LinearLayout layoutAnswer;
public ViewHolderQFile(View v) {
super(v);
qImage = (ImageView) v.findViewById(R.id.img_question);
reply = (ImageView) v.findViewById(R.id.imgReplay);
qText = (TextView) v.findViewById(R.id.txt_question);
aText = (TextView) v.findViewById(R.id.txt_answer);
qUserName = (TextView) v.findViewById(R.id.txt_q_user_name);
aUserName = (TextView) v.findViewById(R.id.txt_a_user_name);
layoutAnswer = (LinearLayout) v.findViewById(R.id.answer_box_item);
}
}
public static class ViewHolderAFile extends RecyclerView.ViewHolder {
ImageView aImage;
ImageView reply;
TextView qText;
TextView aText;
TextView aUserName;
TextView qUserName;
LinearLayout layoutAnswer;
public ViewHolderAFile(View v) {
super(v);
aImage = (ImageView) v.findViewById(R.id.img_answer);
reply = (ImageView) v.findViewById(R.id.imgReplay);
qText = (TextView) v.findViewById(R.id.txt_question);
aText = (TextView) v.findViewById(R.id.txt_answer);
aUserName = (TextView) v.findViewById(R.id.txt_a_user_name);
qUserName = (TextView) v.findViewById(R.id.txt_q_user_name);
layoutAnswer = (LinearLayout) v.findViewById(R.id.answer_box_item);
}
}
public static class ViewHolderQAFile extends RecyclerView.ViewHolder {
ImageView qImage;
ImageView aImage;
ImageView reply;
TextView qText;
TextView aText;
TextView aUserName;
TextView qUserName;
LinearLayout layoutAnswer;
public ViewHolderQAFile(View v) {
super(v);
qImage = (ImageView) v.findViewById(R.id.img_question);
aImage = (ImageView) v.findViewById(R.id.img_answer);
reply = (ImageView) v.findViewById(R.id.imgReplay);
qText = (TextView) v.findViewById(R.id.txt_question);
aText = (TextView) v.findViewById(R.id.txt_answer);
aUserName = (TextView) v.findViewById(R.id.txt_a_user_name);
qUserName = (TextView) v.findViewById(R.id.txt_q_user_name);
layoutAnswer = (LinearLayout) v.findViewById(R.id.answer_box_item);
}
}
public static class ViewHolderUnsent extends RecyclerView.ViewHolder {
TextView unSentQuestion;
TextView unSentReplyText;
ImageView unSentImage;
public ViewHolderUnsent(View v) {
super(v);
unSentQuestion = (TextView) v.findViewById(R.id.txt_unSend_question);
unSentReplyText = (TextView) v.findViewById(R.id.txt_reply_unSend_question);
unSentImage = (ImageView) v.findViewById(R.id.img_unSend_question);
}
}
public static class ViewHolderReply extends RecyclerView.ViewHolder {
TextView replyPastQ;
TextView replyPastA;
TextView replyCurrentQ;
TextView replyCurrentA;
LinearLayout layoutAnswer;
ImageView imgReplay;
public ViewHolderReply(View v) {
super(v);
replyPastQ = (TextView) v.findViewById(R.id.reply_txt_past_question);
replyPastA = (TextView) v.findViewById(R.id.right_reply_txt_past_answer);
replyCurrentQ = (TextView) v.findViewById(R.id.reply_txt_current_question);
replyCurrentA = (TextView) v.findViewById(R.id.right_reply_txt_current_answer);
layoutAnswer = (LinearLayout) v.findViewById(R.id.answer_box_item);
imgReplay = (ImageView) v.findViewById(R.id.imgReplay);
}
}
#Override
public int getItemViewType(int position) {
/* *****************************Handling Inline Parents**************
* *
* 1 for item_message_no_file
* 2 for item_message_question_has_file
* 3 for item_message_answer_has_file
* 4 for item_message_q_a_has_file
* */
if (chatArray.get(position).isNoFile()) {
return 1;
} else if (chatArray.get(position).isMineUnSend()) {
//UnSend
return 2;
} else if (chatArray.get(position).isReply()) {
//Has Reply
return 3;
} else if (chatArray.get(position).isqHasFile()) {
//At this position q has file
return 4;
} else if (chatArray.get(position).isaHasFile()) {
//At this position a has file
return 5;
} else {
//At this position q and a have file
return 6;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Create a new View
//No File
final View item_message_no_file = LayoutInflater.from(mContext).inflate(R.layout.item_message_no_file, parent, false);
//Not Send
final View item_message_un_send = LayoutInflater.from(mContext).inflate(R.layout.item_message_un_sent, parent, false);
//Reply
final View item_message_reply = LayoutInflater.from(mContext).inflate(R.layout.item_message_reply, parent, false);
//Question has File
final View item_message_q_has_file = LayoutInflater.from(mContext).inflate(R.layout.item_message_question_has_file, parent, false);
//Answers has File
final View item_message_a_has_file = LayoutInflater.from(mContext).inflate(R.layout.item_message_answer_has_file, parent, false);
//Question and Answer have file
final View item_message_q_a_has_file = LayoutInflater.from(mContext).inflate(R.layout.item_message_q_a_has_file, parent, false);
if (viewType == 1) {
return new ViewHolderNoFile(item_message_no_file); //For item_message_no_file
} else if (viewType == 2) {
return new ViewHolderUnsent(item_message_un_send); //For item_message_un_send
} else if (viewType == 3) {
return new ViewHolderReply(item_message_reply); //For item_message_reply
} else if (viewType == 4) {
return new ViewHolderQFile(item_message_q_has_file); //For item_message_q_has_file
} else if (viewType == 5) {
return new ViewHolderAFile(item_message_a_has_file); //For item_message_a_has_file
} else {
return new ViewHolderQAFile(item_message_q_a_has_file); //For item_message_q_a_has_file
}
}
/**
* add sent message to adapter
*
* #ArrayList<ChatModel> chatArray of messages
*/
public void addItem(ChatModel newMessage) {
Log.i("CHAT_ADAPTER", "CHAT ARRAY SIZE: " + this.chatArray.size());
this.chatArray.add(newMessage);
//notifyItemInserted(this.chatArray.size()-1);
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
String question;
CourseForumModel cfm = chatArray.get(holder.getAdapterPosition()).getCourseForumModel();
switch (holder.getItemViewType()) {
case 1: //For item_message_no_file
ViewHolderNoFile vhNoFile = (ViewHolderNoFile) holder;
//Set userName of Answer
setUserName(vhNoFile.aUserName, cfm.getCourseForumAUserName());
//Set userName of Question
setUserName(vhNoFile.qUserName, cfm.getCourseForumQUserName());
//Set Question Text
setMessage(vhNoFile.qText, cfm.getCourseForumQuestion());
//Set Answer Text
setMessage(vhNoFile.aText, cfm.getCourseForumAnswer());
vhNoFile.reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentForum.onEvent(fragmentForum, chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumId());
}
});
// check if answer text is empty get answer layout gone
if (vhNoFile.aText.getText() == "") {
vhNoFile.layoutAnswer.setVisibility(View.INVISIBLE);
} else {
vhNoFile.layoutAnswer.setVisibility(View.VISIBLE);
}
break;
case 2: //For item_message_unSent
ViewHolderUnsent vhUnsent = (ViewHolderUnsent) holder;
SendChatModel unSendChat = chatArray.get(holder.getAdapterPosition()).getUnSendChats();
question = unSendChat.getCourseForum().getCourseForumQuestion();
int hasFile = unSendChat.getHasFile();
if (unSendChat.getCourseForum().getCourseForumQuestion() != null) {
vhUnsent.unSentQuestion.setText(question);
} else {
vhUnsent.unSentQuestion.setText("");
}
if (unSendChat.getCourseForum().getCourseForumReplyTo() > 0) {
vhUnsent.unSentReplyText.setText(unSendChat.getCourseForum().getReplyToSummary());
} else {
vhUnsent.unSentReplyText.setText("");
}
//This UnSend Message has a file
if (hasFile == 1) {
String filePath = chatArray.get(holder.getAdapterPosition()).getUnSendChats().getFilePath();
Picasso
.with(mContext)
.load(new File(filePath))
.resize(64, 64)
.into(vhUnsent.unSentImage);
} else {
vhUnsent.unSentImage.setImageResource(android.R.color.transparent);
}
break;
case 3: //For item_message_Reply
ViewHolderReply vRTReply = (ViewHolderReply) holder;
vRTReply.replyPastQ.setText(chatArray.get(holder.getAdapterPosition()).getReplayedMessage().getCourseForumQuestion());
vRTReply.replyPastA.setText(chatArray.get(holder.getAdapterPosition()).getReplayedMessage().getCourseForumAnswer());
vRTReply.replyCurrentQ.setText(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumQuestion());
vRTReply.replyCurrentA.setText(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAnswer());
vRTReply.imgReplay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentForum.onEvent(fragmentForum, chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumId());
}
});
// check if answer text is empty get answer layout gone
if (chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAnswer().equals("")) {
vRTReply.layoutAnswer.setVisibility(View.INVISIBLE);
} else {
vRTReply.layoutAnswer.setVisibility(View.VISIBLE);
}
break;
case 4: //For item_message_q_has_file
ViewHolderQFile vhQFile = (ViewHolderQFile) holder;
setUserName(vhQFile.qUserName, cfm.getCourseForumQUserName());
setUserName(vhQFile.aUserName, cfm.getCourseForumAUserName());
//Set Question Text
setMessage(vhQFile.qText, cfm.getCourseForumQuestion());
//Set Answer Text
setMessage(vhQFile.aText, cfm.getCourseForumAnswer());
loadImage(
vhQFile.qImage,
holder.getAdapterPosition(),
chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumQFile()
);
vhQFile.qImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumQFile());
}
});
vhQFile.reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentForum.onEvent(fragmentForum, chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumId());
}
});
// check if answer text is empty get answer layout gone
if (vhQFile.aText.getText() == "") {
vhQFile.layoutAnswer.setVisibility(View.INVISIBLE);
} else {
vhQFile.layoutAnswer.setVisibility(View.VISIBLE);
}
break;
case 5: //For item_message_a_has_file
ViewHolderAFile vhAFile = (ViewHolderAFile) holder;
setUserName(vhAFile.qUserName, cfm.getCourseForumQUserName());
setUserName(vhAFile.aUserName, cfm.getCourseForumAUserName());
//Set Question Text
setMessage(vhAFile.qText, cfm.getCourseForumQuestion());
//Set Answer Text
setMessage(vhAFile.aText, cfm.getCourseForumAnswer());
loadImage(
vhAFile.aImage,
holder.getAdapterPosition(),
chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAFile()
);
vhAFile.aImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAFile());
}
});
vhAFile.reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentForum.onEvent(fragmentForum, chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumId());
}
});
// check if answer text is empty get answer layout gone
if (vhAFile.aText.getText() == "") {
vhAFile.layoutAnswer.setVisibility(View.INVISIBLE);
} else {
vhAFile.layoutAnswer.setVisibility(View.VISIBLE);
}
break;
case 6: //For item_message_q_a_has_file
ViewHolderQAFile vhQAFile = (ViewHolderQAFile) holder;
setUserName(vhQAFile.qUserName, cfm.getCourseForumQUserName());
setUserName(vhQAFile.aUserName, cfm.getCourseForumAUserName());
//Set Question Text
setMessage(vhQAFile.qText, cfm.getCourseForumQuestion());
//Set Answer Text
setMessage(vhQAFile.aText, cfm.getCourseForumAnswer());
//Here Both Question and Answer have file
loadImage(
vhQAFile.qImage,
holder.getAdapterPosition(),
chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumQFile()
);
loadImage(
vhQAFile.aImage,
holder.getAdapterPosition(),
chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAFile()
);
vhQAFile.qImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumQFile());
}
});
vhQAFile.aImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumAFile());
}
});
vhQAFile.reply.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragmentForum.onEvent(fragmentForum, chatArray.get(holder.getAdapterPosition()).getCourseForumModel().getCourseForumId());
}
});
// check if answer text is empty get answer layout gone
if (vhQAFile.aText.getText() == "") {
vhQAFile.layoutAnswer.setVisibility(View.INVISIBLE);
} else {
vhQAFile.layoutAnswer.setVisibility(View.VISIBLE);
}
break;
}
}
public void update(ArrayList<ChatModel> updatedArray) {
chatArray.clear();
chatArray.addAll(updatedArray);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return chatArray.size();
}
private void setUserName(TextView textView, String name) {
if (name.length() > 0) {
textView.setText(name);
}
}
private void setMessage(TextView textView, String text) {
if (text.length() > 0) {
textView.setText(text);
}
}
private void loadImage(final ImageView view, int position, final int fileId) {
FileModel fileModel = InternetService.getSingleFile(fileId);
String imageAddress = G.DIR_APP + fileModel.getFileName() + "." + fileModel.getFileExtension();
Picasso
.with(mContext)
.load(new File(imageAddress))
.resize(64, 64)
.into(view);
}
private void showDialog(int fileId) {
FileModel fileModel = InternetService.getSingleFile(fileId);
final Bitmap bitmap = BitmapFactory.decodeFile(G.DIR_APP + fileModel.getFileName() + "." + fileModel.getFileExtension());
final Dialog dialog = new Dialog(mContext, R.style.CustomDialog);
dialog.setContentView(R.layout.activity_image_view);
ImageView img = (ImageView) dialog.findViewById(R.id.imgShow);
img.setImageBitmap(bitmap);
Button dismissButton = (Button) dialog.findViewById(R.id.dissbtn);
dismissButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}
And this is an image of recyclerView:
Update:
I got Log of positions in onBindViewHolder method Ans I scrolled from bottom to top Then I got this items in logCat 0-1-2-3-4-5-6-12-13-14-15-16-17!
Items 7-8-9-1-11 doesn't logged!
This is really Important for me.
Thank you for your answers.
RecyclerView reuses existing Views to perform better. Therefore onBindViewHolder gets called and the previous View is updated with the new Values and Styles. If you don't replace an existing Value with the new one you will still see the old one.
From the RecyclerView Docs.
If the user scrolls the list, the Android Support Library brings the already-prepared view holders into view, and creates and binds new ones as necessary. It does not immediately destroy the view holders that have scrolled out of sight; they are kept available, in case the user scrolls back. However, after a certain number of view holders have been created, the Android Support Library does not create new ones. Instead, it rebinds existing view holders as needed by calling onBindViewHolder() for them, specifying a new position. That method updates the view holder's contents, but it reuses the view that was already created for that view holder. The method does not have to perform costly actions like building or inflating a new view.
As Amod Gokhale mentioned. In most cases wrong views appear because of if statements with missing else.
For all your position which you use to retrieve your item inside onBindViewHolder, you should use holder.getAdapterPosition().
P.S. Not related to your question. In your onCreateViewHolder, you are inflating all types of View first and then returning only the one you need based on your viewType. You should check the viewType first and then only inflate the one View you need.
Finally I found the problem.
I am using a viewPager and 3 fragments in it. When I open my chat fragment that contains mentioned recyclerView and scroll up and down all the items will be in wrong places! So I made a Log of the items position in onBindViewHolder() as #Ahmadul Hoq said to me. Then I found items will not go to onBind in serially!
finally I found this problem was about fragment and viewPager.Then I just used of this method to set my recyclerView again when user sweap it to watch.Like this:
#Override
public void setUserVisibleHint(boolean isVisibleToUser){
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
//Setting up recycler view for Chats
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
rvMain.setLayoutManager(mLayoutManager);
mAdapter = new chatAdapter(populateCourseChats(), getActivity() , this);
rvMain.setAdapter(mAdapter);
scrollRecyclerToBottom(); //Scroll recyclerView to bottom
}
}
And Now everything is fine.
But I didn't find it out why this happens?!
If you know Please tell me.
Thank you.

Recyclerview item click not always work and sometimes can work but with more more click (don't know how many click)

Recyclerview item click not always work and sometimes can work but with more more click (don't know how many click).If just click once that can't clicked.
Note few days ago I tried to click once and it's worked, but now when I tried to running again using AS it's not work, even though I not modified that file
My code
public class RecyclerViewAdapterRiwayat extends RecyclerView.Adapter<RecyclerViewAdapterRiwayat.ViewHolder> {
Context context;
private static final String TAG = RecyclerViewAdapterRiwayat.class.getSimpleName();
List<GetDataAdapterRiwayat> getDataAdapter;
ImageLoader imageLoader1;
String FIXURL = "http://192.168.1.101/AndroidFileUpload/";
String url = FIXURL + "uploads/";
String StatusRiwayat;
public RecyclerViewAdapterRiwayat(List<GetDataAdapterRiwayat> getDataAdapter, Context context) {
super();
this.getDataAdapter = getDataAdapter;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_items_riwayat, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder Viewholder, int position) {
final GetDataAdapterRiwayat getDataAdapter1 = getDataAdapter.get(position);
imageLoader1 = ServerImageParseAdapter.getInstance(context).getImageLoader();
imageLoader1.get(url+getDataAdapter1.getFotoSetelahRiwayat(),
ImageLoader.getImageListener(
Viewholder.networkImageView,//Server Image
R.mipmap.ic_launcher,//Before loading server image the default showing image.
android.R.drawable.ic_dialog_alert //Error image if requested image dose not found on server.
)
);
Viewholder.networkImageView.setImageUrl(url+getDataAdapter1.getFotoSetelahRiwayat(), imageLoader1);
Viewholder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "coba nih5 : "+getDataAdapter1.getNamaJalanRiwayat());
Intent intent = new Intent(v.getContext(), DetailRiwayatActivity.class);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return getDataAdapter.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public TextView ImageTitleNameView;
public NetworkImageView networkImageView;
public ViewHolder(View itemView) {
super(itemView);
ImageTitleNameView = (TextView) itemView.findViewById(R.id.textView_item_riwayat);
networkImageView = (NetworkImageView) itemView.findViewById(R.id.VollyNetworkImageView2);
}
}
}
If you only have the issue after scrolling / flinging the RecyclerView, it's a known bug in the SupportLibrary
After a user scrolls, they cannot click on an item in a RecyclerView. (AOSP issue 66996774)
Issuetracker ID 66996774 and also 69823266 because it's still not fixed in 27.0.1. Even though Google states it has fixed it.
Most important: the fix here (by Chris Banes, Googler) works perfectly: https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2
Try this:
class ViewHolder extends RecyclerView.ViewHolder{
public TextView ImageTitleNameView;
public NetworkImageView networkImageView;
public ViewHolder(View itemView) {
super(itemView);
ImageTitleNameView = (TextView) itemView.findViewById(R.id.textView_item_riwayat);
networkImageView = (NetworkImageView) itemView.findViewById(R.id.VollyNetworkImageView2);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getLayoutPosition(); // use this to get item from list
Log.d(TAG, "coba nih5 : "+getDataAdapter1.getNamaJalanRiwayat());
Intent intent = new Intent(v.getContext(), DetailRiwayatActivity.class);
context.startActivity(intent);
}
});
}
Your code
Viewholder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "coba nih5 : "+getDataAdapter1.getNamaJalanRiwayat());
Intent intent = new Intent(v.getContext(), DetailRiwayatActivity.class);
context.startActivity(intent);
}
});
creating new listener every time to the itemView , Instead implement OnClickListener or pass null before assigning new Listener
Viewholder.itemView.setOnClickListener(null);
Viewholder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "coba nih5 : "+getDataAdapter1.getNamaJalanRiwayat());
Intent intent = new Intent(v.getContext(), DetailRiwayatActivity.class);
context.startActivity(intent);
}
});
Or add listener in ViewHolder onCreateViewHolder()
v.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = viewHolder.getAdapterPosition(); // use this to get item from list
Log.d(TAG, "coba nih5 : "+getDataAdapter1.getNamaJalanRiwayat());
Intent intent = new Intent(v.getContext(), DetailRiwayatActivity.class);
context.startActivity(intent);
}
});
Add these to your parent element of R.layout.recyclerview_items_riwayat
android:clickable="false"
android:focusable="false"
That's probably due to the parent's onTouch method which intercepts the touch event. You need to check if there is a parent view like SwipeLayout.

Categories

Resources