recyclerview listview crash when scrolling - android

I'm using RecyclerView listview to show some list values.In this list I have two ImageView and one Textview. When I quickly scroll the list, app gets crashed. It's happened on some devices.Some devices it's worked but not smoothly scroll.
This is my adapter
public class MYAdapter extends RecyclerView.Adapter<MYAdapter.ItemViewHolder> {
private ArrayList<Data_Model> mItems;
private ClickListener clicklistener = null;
private Context context;
public RVAdapter(Context context,ArrayList<Data_Model> arrayList) {
this.context = context;
this.mItems = arrayList;
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mTextView;
private ImageView imageview;
private ImageView mType;
public ItemViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mTextView = (TextView) itemView.findViewById(R.id.list_item);
imageview = (ImageView) itemView.findViewById(R.id.image);
mType = (ImageView) itemView.findViewById(R.id.mtype);
}
#Override
public void onClick(View v) {
if (clicklistener != null) {
clicklistener.itemClicked(v, getAdapterPosition());
}
}
}
public void setClickListener(ClickListener listener) {
this.clicklistener = listener;
}
#Override
public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) {
itemViewHolder.mTextView.setText(mItems.get(i).getTitle());
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeFile(mItems.get(i).getImage(),bmOptions);
itemViewHolder.imageview.setImageBitmap(bitmap);
{
Bitmap bitmaps = BitmapFactory.decodeResource(context.getResources(),R.drawable.music);
itemViewHolder.mType.setImageBitmap(bitmaps);
}
#Override
public ItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_row, viewGroup, false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
}
#Override
public int getItemCount() {
return mItems.size();
}
}
this is my list
Error Message

make sure to recyler image when view onViewRecycled
#Override
public void onViewRecycled(ItemViewHolder holder) {
holder.imageView.setImageBitmap(null);
}
your recyclerview most likely still not smooth enough when scrolled, since you load image synchronously in main thread.
but I think it can prevent crash at some point. so, I suggest you to use image loader library like Picasso or Glide to make sure image is loaded asynchronously and make scrolling in your recyclerview way more smoother.
#Override
public void onBindViewHolder(ItemViewHolder itemViewHolder, int i) {
itemViewHolder.mTextView.setText(mItems.get(i).getTitle());
Picasso.with(itemViewHolder.imageview.getContext()).load(mItems.get(i).getImage()).into(itemViewHolder.imageView);
itemViewHolder.imageview.setImageBitmap(bitmap);
}

Related

Android on click set imageview

so I have an android project that makes use of recyclerview and cardview, where I set a background imageview on click of a card. This is my code:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.Viewholder> {
private ArrayList <Integer> mImages = new ArrayList<>();
public RecyclerViewAdapter( Context mContext, ArrayList<Integer> mImages) {
this.mImages = mImages;
}
#NonNull
#Override
public Viewholder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.itemlist,viewGroup,false);
return new Viewholder(view);
}
#Override
public void onBindViewHolder(#NonNull final Viewholder viewholder, int i) {
viewholder.img.setImageResource(mImages.get(i));
}
#Override
public int getItemCount() {
return mImages.size();
}
public class Viewholder extends RecyclerView.ViewHolder implements View.OnClickListener{
ImageView img;
ImageView imv;
public Viewholder(#NonNull View itemView) {
super(itemView);
img = itemView.findViewById(R.id.imgview);
imv = itemView.findViewById(R.id.imageView4);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
Log.d("TEST", "Clicked");
int position = getLayoutPosition();
imv.setImageResource(R.drawable.vehicles);
}
}
}
But it doesn't work on click and the app just crashes. How do I resolve this issue?
You must define your itemView as clickable for receiving click events.
android:clickable="true"
please try move onClickListener to onBindViewHolder
#Override
public void onBindViewHolder(#NonNull final Viewholder viewholder, int i) {
viewholder.img.setImageResource(mImages.get(i));
viewholder.img.setOnClickListener(v -> {
// your code
});
}
Please try
itemView.setOnClickListener(new View.OnClickListener{
#Override
public void onClick(View view){
//your code
}
});

Images got changed in recyclerview adapter click

I have used RecyclerView to display data which contains an Image and a TextView as rawitem.
My Adapter class is as below :
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.RecyclerViewHolders> {
private List<MyModel> itemList;
private Context context;
private DisplayImageOptions displayImageOptions;
public MyAdapter(Activity context, List<MyModel> itemList) {
this.itemList = itemList;
this.context = context;
}
#Override
public RecyclerViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.singleview_grid_location, null);
RecyclerViewHolders rcv = new RecyclerViewHolders(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(final RecyclerViewHolders holder, final int position) {
holder.rl_main.setTag(position);
final MyModel mainModel = itemList.get((int) holder.rl_main.getTag());
if (mainModel.is_selected()) {
holder.rl_main.setBackgroundResource(R.drawable.border_theme);
holder.iv_selection.setVisibility(View.VISIBLE);
} else {
holder.rl_main.setBackgroundColor(Color.parseColor("#FFFFFF"));
holder.iv_selection.setVisibility(View.GONE);
}
holder.txt_location_name.setText(mainModel.getLocationName());
if (mainModel.getImagePath() != null && !mainModel.getImagePath().equals("")) {
Constant.getImageLoader().displayImage(mainModel.getImagePath(),
holder.iv_location_photo, Constant.getInstanceImageOptions(R.mipmap.popup_placeholder), new SimpleImageLoadingListener() {
#Override
public void onLoadingStarted(String imageUri, View view2) {
}
#Override
public void onLoadingFailed(String imageUri, View view2, FailReason failReason) {
holder.iv_location_photo.setImageResource(R.mipmap.popup_placeholder);
}
#Override
public void onLoadingComplete(String imageUri, View view2, Bitmap loadedImage) {
}
});
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mainModel.is_selected()) {
mainModel.setIs_selected(false);
} else {
mainModel.setIs_selected(true);
}
itemList.set(position, mainModel);
notifyDataSetChanged();
}
});
}
#Override
public int getItemCount() {
return this.itemList.size();
}
public class RecyclerViewHolders extends RecyclerView.ViewHolder {
public TextView txt_location_name;
public ImageView iv_location_photo;
public CardView card_view;
public ImageView iv_selection;
public RelativeLayout rl_main;
public RecyclerViewHolders(View itemView) {
super(itemView);
txt_location_name = (TextView) itemView.findViewById(R.id.txt_location_name);
iv_location_photo = (ImageView) itemView.findViewById(R.id.iv_location_photo);
card_view = (CardView) itemView.findViewById(R.id.card_view);
iv_selection = (ImageView) itemView.findViewById(R.id.iv_selection);
rl_main = (RelativeLayout) itemView.findViewById(R.id.rl_main);
}
}
}
The issue is that, When I am clicking on view of Recyclerview, The images got changed. Ya, The textview and my selection remains same and works accurate. The issue is image got changed for views.
What might be the issue ? Please, checkout. Thanks.
What is the point of doing this ??
holder.rl_main.setTag(position);
final MyModel mainModel = itemList.get((int) holder.rl_main.getTag());
You need to get the List position from the position parameter itself that onBindView provides you.
Next You should write onClickListener on Class itself and not implement inside the onBindView.Bad Practice and can create some problems.
Override Method. " getItemViewType(int position) ".
After Modifying the model.
You should do notify item added/removed/changed/inserted based on the need and the provide position which you can get from getAdapterPosition.

Selected image in recyclerview is get unselected upon scroll

In my recyclerview has one imageview and textview. I'm changing image of ImageView onn onClickListener. Now the problem is if i click on image of position 3 and scroll down... image of position 8 is also changed and again if i scroll up...image of position 2 is changed.
public class PortraitListviewAdapter extends RecyclerView.Adapter<PortraitListviewAdapter.ViewHolder> {
Context context;
static List<PortraitParentListAdapterBean> list;
static List<String> selectedPosition ;
public PortraitListviewAdapter(Context context, List<PortraitParentListAdapterBean> list) {
this.context = context;
this.list = list;
selectedPosition = new ArrayList<>();
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.listview_parent_portrait, parent, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
PortraitParentListAdapterBean portBean = list.get(position);
Log.i("pos",position+"");
holder.parentHeading.setText(portBean.getHeading());
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
}
}
#Override
public int getItemCount() {
return list.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
protected TextView parentHeading;
protected ImageView parentImage;
public ViewHolder(View itemView) {
super(itemView);
parentHeading = (TextView)itemView.findViewById(R.id.parent_heading);
parentImage = (ImageView)itemView.findViewById(R.id.imageView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPosition.add(list.get(getAdapterPosition()).getHeading());
parentImage.setImageResource(R.drawable.sad);
}
});
}
}
}
the above code is my implementation for recyclerview adapter. please help to understand the concept.
SOLUTION
change
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
}
with
if (selectedPosition.contains(list.get(position).getHeading())){
holder.parentImage.setImageResource(R.drawable.sad);
} else {
holder.parentImage.setImageResource(R.drawable.your_default_drawable);
}
EXPLANATION
When you scroll your RecyclerView the system doesn't recreate always your ViewHolder but reuse one you previously scrolled that is no longer visible, so you need to reset your standard values in order to avoid showing wrong values.

RecyclerView OnClick not working

I have made a horizontal recyclerview inside a fragment. Now when I click on any item I don't see the on click listener working. Here is my code for the Adapter class:
public class FeaturedProductsAdapter extends RecyclerView.Adapter<FeaturedProductsAdapter.CustomViewHolder> {
private List<FeaturedProductInfo> feedItemList;
private Context mContext;
public FeaturedProductsAdapter(Context context, List<FeaturedProductInfo> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
public class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
protected ImageView imageView;
protected TextView textView,priceView;
private Context context;
public CustomViewHolder(View view,Context context) {
super(view);
this.context=context;
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.prodTitle);
this.priceView = (TextView) view.findViewById(R.id.prodPrice);
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int position = getLayoutPosition(); // gets item position
Log.e("Check", position + "");
FeaturedProductInfo user = feedItemList.get(position);//[position];
// We can access the data within the views
Intent intent = new Intent(context, ProductDescription.class);
intent.putExtra("id", user.getId());
mContext.startActivity(intent);
}
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.featured_product_list_item_card, null);
Context context = viewGroup.getContext();
CustomViewHolder viewHolder = new CustomViewHolder(view,context);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
FeaturedProductInfo feedItem = feedItemList.get(i);
//Download image using picasso library
if(!feedItem.getUrl().contains("."))
{
feedItem.setUrl("nothing");
}
Picasso.with(mContext).load(feedItem.getUrl())
.error(R.drawable.unavailable)
.placeholder(R.drawable.unavailable)
.resize(110,110)
.into(customViewHolder.imageView);
//Setting text view title
customViewHolder.textView.setText(feedItem.getTitle());
customViewHolder.priceView.setText(feedItem.getPrice());
//Log.e("Featured: ","SET");
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
}
I think I am not getting how to use the view holder properly. While I have used the same code for recyclerView in another activities and it works like charm.
1.Simple Click Handler within ViewHolder
RecyclerView does not have special provisions for attaching click handlers to items unlike ListView which has the method setOnItemClickListener(). To achieve a similar effect, we can attach click events within the ViewHolder within our adapter:
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
// ...
// Used to cache the views within the item layout for fast access
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView tvName;
public TextView tvHometown;
private Context context;
public ViewHolder(Context context, View itemView) {
super(itemView);
this.tvName = (TextView) itemView.findViewById(R.id.tvName);
this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);
// Store the context
this.context = context;
// Attach a click listener to the entire row view
itemView.setOnClickListener(this);
}
// Handles the row being being clicked
#Override
public void onClick(View view) {
int position = getLayoutPosition(); // gets item position
User user = users.get(position);
// We can access the data within the views
Toast.makeText(context, tvName.getText(), Toast.LENGTH_SHORT).show();
}
}
// ...
}
Another way is my preferred way.. but this is also a fine way to go about it.
My onBindViewHolder
#Override
public void onBindViewHolder(CategoryViewHolder holder, int position) {
Category category = mCategories.get(position);
holder.tvTitle.setText(category.getTitle());
holder.tvDescription.setText(category.getDescription());
holder.rlContainer.setOnClickListener(mClickListener);
holder.rlContainer.setTag(holder);
}
My class level (Adapter object of View.OnClickListner)
View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
CategoryViewHolder holder = (CategoryViewHolder) view.getTag();
int position = holder.getAdapterPosition();
startAppointmentBookingFor(mCategories.get(position));
}
};
so basically attach the listener to any view in your holder (I try to put it on container only), then extract it out on the onclick and handle positions etc.
In ‘CustomViewHolder’ below ‘super(view)’ add
view.setOnClickListener(this)
You’re done
Should work.
Make the following changes to your Adapter:
public class FeaturedProductsAdapter extends RecyclerView.Adapter<FeaturedProductsAdapter.CustomViewHolder> {
private List<FeaturedProductInfo> feedItemList;
private Context mContext;
private OnItemClickListener onItemClickListener;
public FeaturedProductsAdapter(Context context, List<FeaturedProductInfo,OnItemClickListener onItemClickListener> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
this.onItemClickListener = onItemClickListener;
}
public class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
protected ImageView imageView;
protected TextView textView,priceView;
private Context context;
public CustomViewHolder(View view,Context context) {
super(view);
this.context=context;
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.prodTitle);
this.priceView = (TextView) view.findViewById(R.id.prodPrice);
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {
onItemClickListener.onItemClick(getLayoutPosition());
Log.e("Check", position + "");
FeaturedProductInfo user = feedItemList.get(position);//[position];
// We can access the data within the views
Intent intent = new Intent(context, ProductDescription.class);
intent.putExtra("id", user.getId());
mContext.startActivity(intent);
}
}
public interface OnItemClickListener{
void onItemClick(int position);
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.featured_product_list_item_card, null);
Context context = viewGroup.getContext();
CustomViewHolder viewHolder = new CustomViewHolder(view,context);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
FeaturedProductInfo feedItem = feedItemList.get(i);
//Download image using picasso library
if(!feedItem.getUrl().contains("."))
{
feedItem.setUrl("nothing");
}
Picasso.with(mContext).load(feedItem.getUrl())
.error(R.drawable.unavailable)
.placeholder(R.drawable.unavailable)
.resize(110,110)
.into(customViewHolder.imageView);
//Setting text view title
customViewHolder.textView.setText(feedItem.getTitle());
customViewHolder.priceView.setText(feedItem.getPrice());
//Log.e("Featured: ","SET");
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}

Toast message onClick NOT SHOWING (RecycleView)

Im trying show a toast msg when clicked on a item from my RecycleView, Ive tried many examples,
but its not giving me anything. Can somebody give me a different example that i can follow, at the end i wanna set the onClick to show a new fragment. If I can get an example on that, it will be great.
Im using this code:
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.ViewHolder> {
private List<Movie> movies;
private int card_layout;
private Context mContext;
public MovieAdapter(List<Movie> movies, int card_layout, Context context) {
this.movies = movies;
this.card_layout = card_layout;
this.mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
final View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(card_layout, viewGroup, false);
return new ViewHolder(itemView);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
final Movie movie = movies.get(i);
viewHolder.movieImage.setImageDrawable(mContext.getDrawable(movie.getImageResourceId(mContext)));
viewHolder.movieName.setText(movie.mName);
viewHolder.currentMovie = movie;
}
#Override
public int getItemCount(){
return movies.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView movieName;
public ImageView movieImage;
public Movie currentMovie;
public ViewHolder( View itemView) {
super(itemView);
movieName = (TextView) itemView.findViewById(R.id.movieName);
movieImage = (ImageView)itemView.findViewById(R.id.movieImage);
itemView.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View itemView){
Toast.makeText(itemView.getContext(),currentMovie.mName,Toast.LENGTH_SHORT ).show();
}
});
}
}
}
Do I have to implement something in my MainActivity as well?
and please dont get mad with me, Im just a starting with all this. All your help will be appriciated. thanks
Layout is not clickable by default. to make clickable add setClickable to true :
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(
card_layout, viewGroup, false);
itemView.setClickable(true);
itemView.setFocusableInTouchMode(true);
After wasting an hour of time, I found the most appropriate and simplest solution to this problem:
Try this, it will definitely work.No matters whether cards are used in grids or not.
RecyclerView Adapter:
ProductCardRecyclerViewAdapter.java
public class ProductCardRecyclerViewAdapter extends RecyclerView.Adapter<ProductCardViewHolder> {
public final String TAG=getClass().getSimpleName();
Context context;
private List<ProductEntry> productList;
private Integer[] cardImages;
String[] cardTitle;
String[] cardSubtitle;
public ProductCardRecyclerViewAdapter(Context context, Integer[] imageList, String[] cardTitle, String[] cardSubtitle) {
this.cardImages = imageList;
this.cardTitle = cardTitle;
this.cardSubtitle = cardSubtitle;
this.context = context;
}
#NonNull
#Override
public ProductCardViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_card, parent, false);
return new ProductCardViewHolder(layoutView);
}
#Override
public void onBindViewHolder(#NonNull ProductCardViewHolder holder, int position) {
// TODO: Put Recycler ViewHolder Cards binding code here in MDC-102
holder.imgCard.setImageResource(cardImages[position]);
holder.productTitle.setText(cardTitle[position]);
holder.productPrice.setText(cardSubtitle[position]);
holder.productCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick: Material Card clicked "+cardTitle[position]+" : "+context.getClass());
//TODO: Perform card clicked working
Context c = v.getContext();
Toast.makeText(c, cardTitle[position], Toast.LENGTH_SHORT).show();
}
});
}
#Override
public int getItemCount() {
return cardImages.length;
}
}
RecyclerViewHolder
ProductCardViewHolder.java
public class ProductCardViewHolder extends RecyclerView.ViewHolder {
CardView productCard;
ImageView imgCard;
public TextView productTitle;
public TextView productPrice;
public ProductCardViewHolder(#NonNull View itemView) {
super(itemView);
imgCard = itemView.findViewById(R.id.product_image);
productTitle = itemView.findViewById(R.id.product_title);
productPrice = itemView.findViewById(R.id.product_price);
productCard=itemView.findViewById(R.id.cardofproducts);
// TODO: Find and store views from itemView
}
}
Hope, it will help a lot.

Categories

Resources