My app shows video feeds in my app using recyclerview. It seems to have started crashing now out of nowhere and I can't wrap my head around to fix this.
My adapter:
public class VideosAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {
private ArrayList<Object> data = new ArrayList<>();
private Context context;
private int lastItemPosition = -1;
private final int VIEW_TYPE_LIST = 0;
private final int VIEW_TYPE_LOADER = 1;
private final int VIEW_TYPE_NETWORK_ERROR = 2;
private final int VIEW_TYPE_AD = 3;
private boolean isLoading = false;
private LoadMoreListener loadMoreListener;
private int visibleThreshold = 2;
private int lastVisibleItem, totalItemCount;
private VideoListener videoListener;
public VideosAdapter(Context context, RecyclerView mRecyclerView, VideoListener videoListener) {
this.context=context;
this.videoListener = videoListener;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LocalMessageManager.getInstance().send(R.id.recyclerview_scroll);
assert linearLayoutManager != null;
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
int firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition();
if ((firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD) % Constants.ADS.LOAD_ADS_AT_POSITION == 0){
//
int pos = firstVisibleItem + Constants.ADS.NUMBER_OF_ITEMS_BEFORE_REQUEST_AD;
if(pos > lastItemPosition && data.size()>pos && data.get(pos - 1) != null) {
if (!(data.get(pos) instanceof NativeAd)) {
videoListener.requestAds(pos);
}
}
}
if (!isLoading && NetworkUtil.hasConnection(context)) {
if (totalItemCount <= (lastVisibleItem + visibleThreshold)) {
if (loadMoreListener != null) {
loadMoreListener.onLoadMore();
}
isLoading = true;
}
}
}
});
}
#Override
public int getItemViewType(int position) {
if(data.get(position) instanceof Error)return VIEW_TYPE_NETWORK_ERROR;
if(data.get(position) == null)return VIEW_TYPE_LOADER;
if(data.get(position) instanceof NativeAd)return VIEW_TYPE_AD;
return VIEW_TYPE_LIST;
}
public void setData(ArrayList<Object> objectList) {
this.data.clear();
this.data.addAll(objectList);
this.notifyDataSetChanged();
}
public void setMoreData(ArrayList<Videos> videos) {
data.addAll(videos);
this.notifyDataSetChanged();
}
public void setAd(NativeAd ad, int pos) {
if(!(pos>data.size())) {
data.add(pos, ad);
this.notifyItemInserted(pos);
}
}
#Override
public int getItemCount() {
return data != null ? data.size() : 0;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
lastItemPosition = position;
switch (holder.getItemViewType()) {
case VIEW_TYPE_LIST:
final VideoViewHolder viewHolder = (VideoViewHolder) holder;
viewHolder.bindTo((Videos) data.get(position));
break;
case VIEW_TYPE_LOADER:
final ViewLoader viewLoader = (ViewLoader) holder;
viewLoader.rotateLoading.start();
break;
case VIEW_TYPE_NETWORK_ERROR:
StaggeredGridLayoutManager.LayoutParams layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
layoutParams.setFullSpan(true);
holder.itemView.setLayoutParams(layoutParams);
ViewError viewError = (ViewError) holder;
if(SharedPrefernces.getUseNightMode()){
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.white));
}else{
viewError.img.setColorFilter(App.getContext().getResources().getColor(R.color.black));
}
break;
case VIEW_TYPE_AD:
final AdsViewHolder adsViewHolder = (AdsViewHolder) holder;
NativeAd nativeAd = (NativeAd)data.get(position);
adsViewHolder.bind(nativeAd);
break;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int i) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(context);
switch (i) {
case VIEW_TYPE_LIST:
View va;
if(SharedPrefernces.get_feed_type()==0){
va = inflater.inflate(R.layout.large_image_video_list, parent, false);
}else{
va = inflater.inflate(R.layout.video_list, parent, false);
}
viewHolder = new VideoViewHolder(va, videoListener);
break;
case VIEW_TYPE_LOADER:
View ld = inflater.inflate(R.layout.loader, parent, false);
viewHolder = new ViewLoader(ld);
break;
case VIEW_TYPE_NETWORK_ERROR:
View ne = inflater.inflate(R.layout.no_video_stories, parent, false);
viewHolder = new ViewError(ne);
break;
case VIEW_TYPE_AD:
View ads = inflater.inflate(R.layout.ad_item_large, parent, false);
viewHolder = new AdsViewHolder(ads);
break;
}
return viewHolder;
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.pin:
break;
case R.id.share:
break;
}
}
public class ViewLoader extends RecyclerView.ViewHolder {
private RotateLoading rotateLoading;
ViewLoader(View view) {
super(view);
rotateLoading = (RotateLoading) view.findViewById(R.id.rotateloading);
}
}
public class ViewError extends RecyclerView.ViewHolder {
private ImageView img;
ViewError(View view) {
super(view);
img = view.findViewById(R.id.img);
}
}
public void setLoaded(){
data.remove(data.size()-1);
this.notifyItemRemoved(data.size()-1);
isLoading = false;
}
public void setLoadMoreListener(LoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void setLoader(){
data.add(null);
this.notifyItemInserted(data.size()-1);
}
}
Code from the fragment which sets this adapter and also throws the error:
recyclerView = (RecyclerView) layout.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 1));
adapter = new VideosAdapter(getActivity(),recyclerView,this);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(data.size()> 0 && data.get(1) instanceof Videos){
adapter.setLoader();
loadMoreFeeds();
}
}));
recyclerView.setAdapter(adapter);
Error Log:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
at java.util.ArrayList.get(ArrayList.java:437)
I tried to few fixes from other SOF answers but couldn't understand what went wrong with my code considering it was running fine and it suddenly seems to have started crashing. I removed a header in the adapter if that matters.
Your problem is in this piece of code:
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(data.size()> 0 && data.get(1) instanceof Videos){
adapter.setLoader();
loadMoreFeeds();
}
}));
you are checking if the length of your array is bigger than 0, but it means that there could also be only one element. So, therefore, you should change this line to:
if(data.size() > 0 && data.get(0) instanceof Videos)
or to:
if(data.size() > 1 && data.get(1) instanceof Videos)
Remember that the count of elements in the array starts at 0.
Hope it helps!
Related
I got a weird exception in the function onCreateViewHolder inside my custom adapter. Probably because getItemViewType function returns different values as expected.
This is how getItemViewType function looks like:
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
#Override
public int getItemViewType(int position) {
if (position == 0)
return TYPE_HEADER;
return TYPE_ITEM;
}
As you can see, it returns 0 or 1 only, no other option.
This is how onCreateViewHolder function looks like:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_groups, null);
return new HeaderHolder(view);
} else if(viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.explore_group_row, null);
return new ItemHolder(view);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " make sure your using types correctly");
}
However, I got some crashes from crashlytics that there is no type that matches with viewTypes of 6, 7, 8, 11, etc.. Not sure where it gets from...
In addition, I can't reproduce this issue, no idea how it happens.
I saw a similar issue in this thread but no solution.
Here you can see the exception from crashlytics:
Fatal Exception: java.lang.RuntimeException: there is no type that matches the type 6 make sure your using types correctly
at com.example.eliran.forum.GroupsFragment$GroupsAdapter.onCreateViewHolder(GroupsFragment.java:72)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5)
at androidx.recyclerview.widget.RecyclerView$Recycler.a(RecyclerView.java:295)
at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:14)
at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:15)
at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:22)
at androidx.recyclerview.widget.GapWorker.a(GapWorker.java:3)
at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:71)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7078)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Here's the full code of the adapter:
private class GroupsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_groups, null);
return new HeaderHolder(view);
} else if(viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.explore_group_row, null);
return new ItemHolder(view);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " make sure your using types correctly");
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
if (holder instanceof ItemHolder) {
ItemHolder theHolder = (ItemHolder) holder;
Group group = groups.get(i - 1);
theHolder.title.setText(group.getTitle());
theHolder.description.setText(group.getDescription());
if(group.getImage() != null) {
Picasso.get()
.load(group.getImage())
.fit()
.into(theHolder.image);
} else {
Picasso.get()
.load(R.drawable.profile_picture_holder)
.fit()
.into(theHolder.image);
}
} else if (holder instanceof HeaderHolder){
HeaderHolder theHolder = (HeaderHolder) holder;
if (showMyGroupsPb) {
theHolder.myGroupsPb.setVisibility(View.VISIBLE);
theHolder.myGroupSectionHeader.setOnBtnListener(null);
} else {
theHolder.myGroupsPb.setVisibility(View.GONE);
theHolder.myGroupSectionHeader.setOnBtnListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(rootView.getContext(), MyGroupsActivity.class);
intent.putExtra("groups", myGroups);
startActivityForResult(intent, TheFinals.JOIN_LEAVE_GROUP_CODE);
}
});
}
}
}
#Override
public int getItemViewType(int position) {
if (position == 0)
return TYPE_HEADER;
return TYPE_ITEM;
}
#Override
public int getItemCount() {
return groups.size() + 1;
}
class HeaderHolder extends RecyclerView.ViewHolder {
private ProgressBar myGroupsPb;
private SectionHeader myGroupSectionHeader;
public HeaderHolder(View view) {
super(view);
myGroupsRv = view.findViewById(R.id.groupsRecyclerView);
myGroupsPb = view.findViewById(R.id.pb);
LinearLayoutManager horizontalLayoutManager
= new LinearLayoutManager(rootView.getContext(), LinearLayoutManager.HORIZONTAL, false);
myGroupsRv.setLayoutManager(horizontalLayoutManager);
myGroupsRv.setAdapter(myGroupAdapter);
myGroupSectionHeader = view.findViewById(R.id.myGroupSectionHeader);
}
}
class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
protected TextView title;
protected ImageView image;
protected TextView description;
public ItemHolder(View view) {
super(view);
this.title = view.findViewById(R.id.title);
this.image = view.findViewById(R.id.image);
this.description = view.findViewById(R.id.description);
view.setOnClickListener(this);
}
#Override
public void onClick(View view) {
int itemPosition = groupsRecyclerView.getChildLayoutPosition(view) - 1;
selectedGroupIndex = itemPosition;
Intent intent = new Intent(rootView.getContext(), GroupActivity.class);
intent.putExtra("group", groups.get(itemPosition));
startActivityForResult(intent, TheFinals.JOIN_LEAVE_GROUP_CODE);
}
}
}
I'm trying to set up a Recyclerview with multiple lists(like Facebook ads and user feed) from 2 API endpoints but getting some errors when I try to paginate the list(load more).
Here is my code. I've tried to call the addAll method in my activity after loading the two lists from the different API endpoints but I get an error(I also call this method in my loadMore listener[paginate stuff]).
private static final int TYPE_VIDEO = 0;
private static final int TYPE_PROMOTED_VIDEO = 1;
private static final int TYPE_LOADING = 3;
private Context context;
List<Video> videosList;
List<Promoted> promotedVideosList;
private boolean isLoadingAdded = true;
public MyAdapter(Context context){
this.context = context;
//Initalization stuffs
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case TYPE_VIDEO:
View viewVideo = inflater.inflate(R.layout.item_video, parent, false);
viewHolder = new VideoVH(viewVideo);
break;
case TYPE_PROMOTED_VIDEO:
View viewPromoted = inflater.inflate(R.layout.item_promoted_video, parent, false);
viewHolder = new PromotedVH(viewPromoted);
break;
case TYPE_LOADING:
View viewLoading = inflater.inflate(R.layout.item_loading, parent, false);
viewHolder = new LoadingVH(viewLoading);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
switch (getItemViewType(position)) {
case TYPE_VIDEO:
//DO something when it a normal video
break;
case TYPE_PROMOTED_VIDEO:
//DO something when it's a promoted video
break;
case TYPE_LOADING:
//Loading view
break;
}
}
public void add(Video video, Promoted promoted) {
Toast.makeText(context, "Not Null", Toast.LENGTH_SHORT).show();
videosList.add(video);
promotedVideosList.add(promoted);
notifyItemInserted(videosList.size() + promotedVideosList.size() - 1);
}
public void addAll(List<Video> videoList, List<Promoted> promotedList) {
add(addVideo(videoList), addPromoted(promotedList));
}
private Video addVideo(List<Video> videoList){
for (Video result : videoList) return result;
return null;
}
private Promoted addPromoted(List<Promoted> promotedList{
for (Promoted result : promotedList) return result;
return null;
}
#Override
public int getItemCount() {
return videosList == null && promotedVideosList == null ? 0 : this.videosList.size() + this.promotedVideosList.size();
}
#Override
public int getItemViewType(int position) {
int videoSize = this.videosList.size();
int promotedSize = this.promotedVideosList.size();
if(position < videoSize){
return TYPE_VIDEO;
}
if(position - videoSize < promotedSize){
return TYPE_PROMOTED_VIDEO;
}
if (position == promotedSize + videoSize - 1 && isLoadingAdded){
return TYPE_LOADING;
}
return -1;
}
public static class VideoVH extends RecyclerView.ViewHolder{
VideoVH(View itemView) {
super(itemView);
//findviewbyid stuff
}
}
public static class PromotedVH extends RecyclerView.ViewHolder{
public PromotedVH(View itemView) {
super(itemView);
//findviewbyid stuff
}
}
public static class LoadingVH extends RecyclerView.ViewHolder{
#BindView(R.id.loading_progress)
ProgressBar loading;
public LoadingVH(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
I expected this to work but somehow it doesn't and I know I'm not doing something right.
Here is a snippet from my logcat.
java.lang.NullPointerException: Attempt to invoke interface method'boolean java.util.List.add(java.lang.Object)' on a null object reference
at com.myproject.adapters.MyAdapter.add(MyAdapter.java:508)
at com.myproject.adapters.MyAdapter.addAll(MyAdapter.java:515)
Have you initialize the lists before add data into it.In your constructor you must initialize all lists.
For Example : videosList = new List();
likewise
You are not initializing videosList and promotedVideosList . Do this
public MyAdapter(Context context){
//Initalization stuffs
this.context = context;
videosList=new ArrayList();
promotedVideosList=new ArrayList();
}
I have a little bit problem.In my activity there is two Adapter one is for color selection and another is for size selection. While i clicked one of the item of color then recently the available size adapter should be change but i got problem in size adapter. it changes only when i click the size item. I research and try to solve problem but it doesnt works for me.
Here is my code.
AddToCartActivity.java
public class AddToCartActivity extends BaseActivity{
#Override
protected int getLayout() {
return R.layout.activity_add_to_cart;
}
#Override
protected void init() {
//api called here
}
// response of api
#Override
public void productDetail(ProductCommonModel productCommonModel,
ArrayList<ProductChildModel> productChildModels, HashMap<Integer,
ArrayList<ChildAttributeModel>> childWithAttribute, HashMap<Integer,
ArrayList<ChildImageModel>> childWithImages,
ArrayList<com.hazesoft.dokan.singleproductdetail.model.ColorModel>
colorModels, ArrayList<SizeModel> sizeModels,
ArrayList<RelatedProductModel> relatedProductModels) {
this.productCommonModel = productCommonModel;
this.productChildModels = productChildModels;
this.childWithAttribute = childWithAttribute;
this.childWithImages = childWithImages;
this.colorModels = colorModels;
this.sizeModels = sizeModels;
this.relatedProductModels = relatedProductModels;
tvProductName.setText(productCommonModel.getName());
if (productCommonModel.getSpecialPrice() == 0) {
tvSellingPrice.setText(getString(R.string.rs) + productCommonModel.getSellingPrice());
tvDiscount.setVisibility(View.GONE);
tvSpecialPrice.setVisibility(View.GONE);
} else {
tvSpecialPrice.setText(getString(R.string.rs) + productCommonModel.getSpecialPrice());
tvSellingPrice.setText(getString(R.string.rs) + productCommonModel.getSellingPrice());
tvSellingPrice.setPaintFlags(tvSellingPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
tvDiscount.setText(productCommonModel.getDiscount() + getString(R.string.percentage));
}
setChildDetail(childWithAttribute, productChildModels);
setColorModel(colorModels);
setSizeModel(sizeModels);
quantity = Integer.parseInt(tvQuantityCart.getText().toString());
}
// setcolor adapter
private void setColorModel(ArrayList<ColorModel> colorModels) {
MyColorGridViewAdapter adapter = new MyColorGridViewAdapter(this, colorModels);
gvColor.setAdapter(adapter);
gvColor.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
adapter.setSelectedPostion(position);
adapter.notifyDataSetChanged();
}
});
}
// set size adapter
private void setSizeModel(ArrayList<SizeModel> sizeModels) {
sizeCustomModels = new ArrayList<>();
for(int i=0;i<sizeModels.size();i++){
sizeCustomModels.add(new SizeCustomModel(sizeModels.get(i).getAttName(),0));
}
setCustomSizeModelToAdapter(sizeCustomModels);
}
// this is code when i click color and change the size adapter but size doesnt change recently only changes when i click any item of the size
public void getSelectedC0lor(String color) {
selectedColor = color;
selectedSize=null;
sizeCustomModels = new ArrayList<>();
availableSize = new ArrayList<>();
for (int i = 0; i < skuColorSIzeList.size(); i++) {
if (skuColorSIzeList.get(i).getColor().equals(selectedColor)) {
availableSize.add(skuColorSIzeList.get(i).getSize());
}
}
for(int i=0;i<sizeModels.size();i++){
String size = null;
int status=0;
for(int j=0;j<availableSize.size();j++){
if(sizeModels.get(i).getAttName().equals(availableSize.get(j))){
size = sizeModels.get(i).getAttName();
status = 1;
break;
}else {
size = sizeModels.get(i).getAttName();
status = 0;
}
}
sizeCustomModels.add(new SizeCustomModel(size,status));
}
sizeRecylerAdapter.getNewModel(sizeCustomModels);
/*sizeRecylerAdapter = new MyCustomSizeRecylerAdapter(sizeCustomModels,this);
rvSize.setAdapter(sizeRecylerAdapter);
sizeRecylerAdapter.notifyDataSetChanged();*/
/*setCustomSizeModelToAdapter(sizeCustomModels);*/
}
}
MyColorGridViewAdapter.java
public class MyColorGridViewAdapter extends BaseAdapter {
Context context;
List<ColorModel> colorModelList;
String select_color;
boolean ch =false;
int checkPosition = -1;
public MyColorGridViewAdapter(Context context, List<ColorModel> colorModelList) {
this.context = context;
this.colorModelList = colorModelList;
}
public void setSelectedPostion(int postion){
this.checkPosition = postion;
}
#Override
public int getCount() {
return colorModelList.size();
}
#Override
public Object getItem(int position) {
return colorModelList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if(convertView==null){
convertView = LayoutInflater.from(context).inflate(R.layout.custom_color_list_item,null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
Picasso.with(context).load(colorModelList.get(position).getImage()).into(holder.ivImage);
holder.tvColorName.setText(colorModelList.get(position).getAttName());
if(checkPosition==position){
holder.ivChecked.setVisibility(View.VISIBLE);
select_color = colorModelList.get(position).getAttName();
if( context instanceof AddToCartActivity){
((AddToCartActivity) context).getSelectedC0lor(select_color);
}
}else {
holder.ivChecked.setVisibility(View.GONE);
}
if(colorModelList.size()==1){
holder.ivChecked.setVisibility(View.VISIBLE);
select_color = colorModelList.get(position).getAttName();
if( context instanceof AddToCartActivity){
((AddToCartActivity) context).getSelectedC0lor(select_color);
}
}
return convertView;
}
class ViewHolder{
#BindView(R.id.view)
LinearLayout view;
#BindView(R.id.tv_color_name)
TextViewHelper tvColorName;
#BindView(R.id.iv_image)
ImageView ivImage;
#BindView(R.id.iv_checked)
ImageView ivChecked;
public ViewHolder(View view) {
ButterKnife.bind(this,view);
}
}
}
MyCustomSizeRecylerAdapter.java
public class MyCustomSizeRecylerAdapter extends RecyclerView.Adapter<MyCustomSizeRecylerAdapter.MyViewHolder> {
ArrayList<SizeCustomModel> sizeModels;
Context context;
int checkPosition = -1;
String selectedSize;
public MyCustomSizeRecylerAdapter(ArrayList<SizeCustomModel> sizeModels, Context context) {
this.sizeModels = sizeModels;
this.context = context;
}
public void getNewModel(ArrayList<SizeCustomModel> customModels) {
sizeModels.clear();
this.sizeModels = customModels;
selectedSize = null;
Log.d("sizemodel", "getNewModel: " + new Gson().toJson(sizeModels));
notifyDataSetChanged();
}
public void getSelectedPosition(int position) {
checkPosition = position;
notifyDataSetChanged();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.size_adapter, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_sizeName.setText(sizeModels.get(position).getSize());
holder.ll_sizeAdapter.setBackgroundResource(R.drawable.ellipse_register);
if (sizeModels.get(position).getStock_Status() == 0) {
holder.ll_mainview.setClickable(false);
holder.ll_sizeAdapter.setBackgroundResource(R.color.blue_700);
} else if (sizeModels.get(position).getStock_Status() == 1) {
holder.ll_sizeAdapter.setBackgroundResource(R.drawable.ellipse_register);
if (checkPosition == position) {
holder.ll_sizeAdapter.setBackgroundResource(R.drawable.ellipse_green);
holder.tv_sizeName.setTextColor(context.getResources().getColor(R.color.white));
selectedSize = sizeModels.get(position).getSize();
if (context instanceof AddToCartActivity) {
((AddToCartActivity) context).getSelectSize(selectedSize);
}
} else {
holder.ll_sizeAdapter.setBackgroundResource(R.drawable.ellipse_register);
holder.tv_sizeName.setTextColor(context.getResources().getColor(R.color.tv_black));
}
if (sizeModels.size() == 1) {
holder.ll_sizeAdapter.setBackgroundResource(R.drawable.ellipse_green);
holder.tv_sizeName.setTextColor(context.getResources().getColor(R.color.white));
selectedSize = sizeModels.get(position).getSize();
if (context instanceof AddToCartActivity) {
((AddToCartActivity) context).getSelectSize(selectedSize);
}
}
}
}
#Override
public int getItemCount() {
return sizeModels.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.tv_sizeName)
TextView tv_sizeName;
#BindView(R.id.ll_sizeAdapter)
LinearLayout ll_sizeAdapter;
#BindView(R.id.main_view)
LinearLayout ll_mainview;
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
At first both adapter will set data and after click color item the size adapter must be change but it only changes when i click any of the item. adapter.notifyDataSetChanged() doesnt work here for me.
Both Adapter set
When i click color item but doesnt change size adapter
when i click size item only change size adapter
Use Interface to bridge with two adapter and communicate with each other.
When scroll recyclerview some items mixes. After I add ads after every 15 items, holder get wrong data. Some items are vip items. I will change background color of these items. But when I scroll it dublicates mixes. How can I solve?
This is my adapter
private Context mCtx;
private List<Car> carList;
private RecyclerViewAnimator mAnimator;
private int AD_TYPE=1;
private int CONTENT_TYPE=2;
private int LIST_AD_DELTA=15;
public ProductAllCarAdapter(RecyclerView recyclerView,Context mCtx, List<Car> carList) {
this.mCtx = mCtx;
this.carList = carList;
mAnimator = new RecyclerViewAnimator(recyclerView);
}
#Override
public ProductAllCarAdapter.ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == AD_TYPE){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_add_item, null);
ProductAllCarAdapter.ProductViewHolder vh = new ProductAllCarAdapter.ProductViewHolder(itemView);
mAnimator.onCreateViewHolder(itemView);
return vh;
} else {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_car_item, null);
ProductAllCarAdapter.ProductViewHolder vh = new ProductAllCarAdapter.ProductViewHolder(itemView);
mAnimator.onCreateViewHolder(itemView);
return vh;
}
}
#Override
public int getItemViewType(int position) {
if (position>0 && position % LIST_AD_DELTA == 0)
return AD_TYPE;
return CONTENT_TYPE;
}
#Override
public void onBindViewHolder(ProductAllCarAdapter.ProductViewHolder holder, int position) {
if (getItemViewType(position) == CONTENT_TYPE) {
final Car car = carList.get(holder.getAdapterPosition());
GlideApp.with(mCtx).load(car.getImg()).into(holder.imageView);
if (car.getVip() == 1) {
holder.relativeLayout.setBackgroundColor(ContextCompat.getColor(mCtx, R.color.colorVip));
holder.imageViewVIP.setVisibility(View.VISIBLE);
}
final String carid = String.valueOf(car.getCarid());
mAnimator.onBindViewHolder(holder.itemView, position);
} else {
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Context mcontext = view.getContext();
Bundle bundle = ActivityOptionsCompat.makeCustomAnimation(mcontext, android.R.anim.fade_in, android.R.anim.fade_out).toBundle();
Intent intent = new Intent(mcontext, AdsItem.class);
mcontext.startActivity(intent, bundle);
}
});
mAnimator.onBindViewHolder(holder.itemView, position);
}
}
private int getRealPosition(int position) {
if (LIST_AD_DELTA == 0) {
return position;
} else {
return position - position / LIST_AD_DELTA;
}
}
#Override
public long getItemId(int position) { return position; }
#Override
public int getItemCount() {
int additionalContent = 0;
if (carList.size() > 0 && carList.size() > LIST_AD_DELTA) {
additionalContent = ( carList.size() / LIST_AD_DELTA);
}
return carList.size() + additionalContent;
}
public static class ProductViewHolder extends RecyclerView.ViewHolder {
private View mView;
ImageView imageView, imageViewVIP;
RelativeLayout relativeLayout;
public ProductViewHolder(View itemView) {
super(itemView);
mView = itemView;
imageView = itemView.findViewById(R.id.imageView);
imageViewVIP = itemView.findViewById(R.id.imageViewVIP);
relativeLayout = itemView.findViewById(R.id.relativeLayoutpc);
}
public void setOnClickListener(View.OnClickListener listener) {
mView.setOnClickListener(listener);
}
}
I think problem onBindViewHolder function use wrong holder. ArrayList also return true value but on scroll it mixes.
You just have to add the corresponding else of the following if statement block.
if (car.getVip() == 1) {
holder.relativeLayout.setBackgroundColor(ContextCompat.getColor(mCtx, R.color.colorVip));
holder.imageViewVIP.setVisibility(View.VISIBLE);
} else {
holder.relativeLayout.setBackgroundColor(ContextCompat.getColor(mCtx, R.color.colorNormal));
holder.imageViewVIP.setVisibility(View.GONE);
}
This is inside your onBindViewHolder function where the view type is CONTENT_TYPE.
Hope that solves your problem.
I want to implement a simple custom multiselection RecyclerView.
My problem is when I select the first CardView element in the screen, the tenth Card is also selected (When I select the second, the eleventh card is selected etc.). I have tried many different such as using `notifyItemChanged(pos) but I always end up to the same bug.
Here is the code if the my custom class.
public class StudentRecyclerAdapter extends RecyclerView.Adapter<StudentRecyclerAdapter.CustomViewHolder> {
private List<Student> studentListItemList;
private Context mContext;
private Students students;
private Set<Integer> studensToBeRemoved;
private List<Boolean> selected;
public StudentRecyclerAdapter(Context context, List<Student> studentListItemList, Students students) {
this.studentListItemList = studentListItemList;
this.mContext = context;
this.studensToBeRemoved = new HashSet<>();
this.students = students;
selected= new ArrayList<>();
for(int i=0;i<studentListItemList.size();i++)
selected.add(false);
}
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomViewHolder holder = (CustomViewHolder) view.getTag();
int position = holder.getAdapterPosition();
Student studentListItem = studentListItemList.get(position);
Bundle extras = new Bundle();
extras.putInt("id", studentListItem.getId());
extras.putString("name", studentListItem.getName());
extras.putString("surname", studentListItem.getSurname());
extras.putLong("date", studentListItem.getLongBirthday());
extras.putString("photo", studentListItem.getImage());
Intent intent = new Intent(mContext, ProfileStudent.class);
intent.putExtras(extras);
mContext.startActivity(intent);
}
};
View.OnLongClickListener longClickListener = view -> {
final CustomViewHolder holder = (CustomViewHolder) view.getTag();
int pos = holder.getAdapterPosition();
if (!selected.get(pos)) {
holder.stud_card_view.setCardBackgroundColor(Color.GREEN);
studensToBeRemoved.add(studentListItemList.get(pos).getId());
selected.set(pos,true);
} else {
holder.stud_card_view.setCardBackgroundColor(Color.WHITE);
studensToBeRemoved.remove(studentListItemList.get(pos).getId());
selected.set(pos,false);
}
if (studensToBeRemoved.size() > 0)
students.onMethodCallback(true);
else
students.onMethodCallback(false);
StringBuilder stringBuilder= new StringBuilder();
for(Integer integer : studensToBeRemoved)
stringBuilder.append(integer).append(", ");
Toast.makeText(mContext,String.valueOf(pos)+ ": "+stringBuilder.toString(),Toast.LENGTH_LONG).show();
return true;
};
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.student_list_row, null);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
view.setLayoutParams(lp);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i, List<Object> payload) {
if (payload.size() == 1) {
if ((boolean) payload.get(0)) {
customViewHolder.stud_card_view.setCardBackgroundColor(Color.GREEN);
studensToBeRemoved.add(studentListItemList.get(i).getId());
} else {
customViewHolder.stud_card_view.setCardBackgroundColor(Color.WHITE);
studensToBeRemoved.remove(studentListItemList.get(i).getId());
}
if (studensToBeRemoved.size() > 0)
students.onMethodCallback(true);
else
students.onMethodCallback(false);
} else {
Student studentListItem = studentListItemList.get(i);
Picasso.with(mContext).load(studentListItem.getImage())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
customViewHolder.textView.setText(studentListItem.getName() + " " + studentListItem.getSurname());
customViewHolder.stud_card_view.setTag(customViewHolder);
customViewHolder.stud_card_view.setOnClickListener(clickListener);
customViewHolder.stud_card_view.setOnLongClickListener(longClickListener);
}
}
#Override
public int getItemCount() {
return (null != studentListItemList ? studentListItemList.size() : 0);
}
public void setFilter(ArrayList<Student> newList) {
studentListItemList = new ArrayList<>();
studentListItemList.addAll(newList);
notifyDataSetChanged();
}
public Set<Integer> getStudensToBeRemoved() {
return studensToBeRemoved;
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
protected CardView stud_card_view;
public CustomViewHolder(View view) {
super(view);
this.imageView = view.findViewById(R.id.stud_list_pic);
this.textView = view.findViewById(R.id.stud_list_name);
this.stud_card_view = view.findViewById(R.id.stud_card_view);
}
}
}
PS. The payload check I have is because i have also implemented a selectAll() method (Which I call from the fragment host the RecyclerView) which uses the notifyItemRangeChanged() which is works properly.
Finally even the the 10th entry is also checked the studensToBeRemoved.add(studentListItemList.get(pos).getId()); for the 10th entry is never called actually. (The
Toast.makeText(mContext,String.valueOf(pos)+ ": "+stringBuilder.toString(),Toast.LENGTH_LONG).show();
in the end of onLongClickListener shows only the correct values every time ( e.g. when is select the first entry it shows "1: 1") although entry 10 is also selected). Finally if I select entry 10 the opposite happens (entry 1 is also selected).
Any Ideas whats going wrong? I can also provide some screenshots or more details if needed.
Thanks!
I managed to fix it. So here is the correct code in case someone wants to implement a simple RecyclerView with multi-selection. I hope it helps.
public class StudentRecyclerAdapter extends RecyclerView.Adapter<StudentRecyclerAdapter.CustomViewHolder> {
private List<Student> studentListItemList;
private Context mContext;
private StudentsFragment students;
private Set<Integer> studensToBeRemoved;
private List<Boolean> selected;
private View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomViewHolder holder = (CustomViewHolder) view.getTag();
int pos = holder.getAdapterPosition();
if (studensToBeRemoved.size() == 0) {
Student studentListItem = studentListItemList.get(pos);
Bundle extras = new Bundle();
extras.putInt("id", studentListItem.getId());
extras.putString("name", studentListItem.getName());
extras.putString("surname", studentListItem.getSurname());
extras.putLong("date", studentListItem.getLongBirthday());
extras.putString("photo", studentListItem.getImage());
Intent intent = new Intent(mContext, ProfileStudent.class);
intent.putExtras(extras);
mContext.startActivity(intent);
} else {
if (!selected.get(pos)) {
holder.stud_card_view.setCardBackgroundColor(Color.GREEN);
studensToBeRemoved.add(studentListItemList.get(pos).getId());
selected.set(pos, true);
} else {
holder.stud_card_view.setCardBackgroundColor(Color.WHITE);
studensToBeRemoved.remove(studentListItemList.get(pos).getId());
selected.set(pos, false);
}
if (studensToBeRemoved.size() > 0)
students.onMethodCallback(true);
else
students.onMethodCallback(false);
}
}
};
private View.OnLongClickListener longClickListener = view -> {
final CustomViewHolder holder = (CustomViewHolder) view.getTag();
int pos = holder.getAdapterPosition();
if (!selected.get(pos)) {
holder.stud_card_view.setCardBackgroundColor(Color.GREEN);
studensToBeRemoved.add(studentListItemList.get(pos).getId());
selected.set(pos, true);
} else {
holder.stud_card_view.setCardBackgroundColor(Color.WHITE);
studensToBeRemoved.remove(studentListItemList.get(pos).getId());
selected.set(pos, false);
}
if (studensToBeRemoved.size() > 0)
students.onMethodCallback(true);
else
students.onMethodCallback(false);
return true;
};
public StudentRecyclerAdapter(Context context, List<Student> studentListItemList, Students students) {
this.studentListItemList = studentListItemList;
this.mContext = context;
this.studensToBeRemoved = new HashSet<>();
this.students = students;
selected = new ArrayList<>();
for (int i = 0; i < studentListItemList.size(); i++)
selected.add(false);
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.student_list_row, null);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
view.setLayoutParams(lp);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
Student studentListItem = studentListItemList.get(i);
Picasso.with(mContext).load(studentListItem.getImage())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
customViewHolder.textView.setText(studentListItem.getName() + " " + studentListItem.getSurname());
customViewHolder.stud_card_view.setTag(customViewHolder);
customViewHolder.edit_button.setTag(customViewHolder);
customViewHolder.stud_card_view.setOnClickListener(clickListener);
if (!selected.get(i))
customViewHolder.stud_card_view.setCardBackgroundColor(Color.WHITE);
else
customViewHolder.stud_card_view.setCardBackgroundColor(Color.GREEN);
customViewHolder.stud_card_view.setOnLongClickListener(longClickListener);
customViewHolder.stud_card_view.setOnClickListener(clickListener);
customViewHolder.edit_button.setOnClickListener(clickListener);
}
#Override
public int getItemCount() {
return (null != studentListItemList ? studentListItemList.size() : 0);
}
public void setFilter(ArrayList<Student> newList) {
studentListItemList = new ArrayList<>();
studentListItemList.addAll(newList);
notifyDataSetChanged();
}
public Set<Integer> getStudensToBeRemoved() {
return studensToBeRemoved;
}
public void setSelected(boolean b) {
if (b) {
for (int i = 0; i < selected.size(); i++) {
studensToBeRemoved.add(studentListItemList.get(i).getId());
selected.set(i, true);
}
students.onMethodCallback(true);
} else {
for (int i = 0; i < selected.size(); i++) {
selected.set(i, false);
studensToBeRemoved.remove(studentListItemList.get(i).getId());
}
students.onMethodCallback(false);
}
notifyItemRangeChanged(0, getItemCount());
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
protected CardView stud_card_view;
protected ImageButton edit_button;
public CustomViewHolder(View view) {
super(view);
this.imageView = view.findViewById(R.id.stud_list_pic);
this.textView = view.findViewById(R.id.stud_list_name);
this.stud_card_view = view.findViewById(R.id.stud_card_view);
this.edit_button = view.findViewById(R.id.student_edit_btn);
edit_button.bringToFront();
}
}
}
The students.onMethodCallback() function informs the host fragment to show/hide the delete button. In order to select/deselect all element at once all you have to do is to call the setSelected(true/false) method.