0

I have a recycerview. it has item click event in onCreateViewHolder method and an imageview click event on onBindViewHolder method. Surprisingly while recyclerview loads for the first time first and last item click works after second click then after it works on every click if it is not scrolled.Again when i scroll the recyclerview then same happen for the first and last item like first load. I can not figure out what is the problem

Below is my recyclerview layout @+id/recyclerViewForFilteredCourses is the recyclerview

    <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activities.CoursesActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <include layout="@layout/toolbar_with_search"
            android:id="@+id/toolbar" />

        <com.github.ybq.android.spinkit.SpinKitView
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            app:SpinKit_Color="@color/textColorGrey"
            android:visibility="gone"
            android:elevation="200dp"
            style="@style/SpinKitView.Circle"/>

        <!--This textview and the recycler view is responsible for filtered course section-->
        <TextView
            android:id="@+id/filterResultTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Showing X Courses"
            android:layout_below="@+id/toolbar"
            style="@style/headerTitleLabel"/>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerViewForFilteredCourses"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/filterResultTitle"
            android:layout_above="@+id/bottomNavigationView"
            android:paddingHorizontal="14dp"
            android:clipToPadding="false"
            android:layout_marginTop="10dp"
            android:overScrollMode="never"/>

        <!--This is the floating filter button-->
        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/floatingFilterButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="25dp"
            android:layout_marginBottom="25dp"
            android:layout_alignParentBottom="true"
            android:backgroundTint="#273647"
            android:elevation="6dp"
            app:fabSize="normal"
            app:borderWidth="0dp"
            android:src="@drawable/filter"
            android:onClick="handleFilterButton" />
    </RelativeLayout>

    <androidx.core.widget.NestedScrollView
        android:id="@+id/bottomSheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FEFFFF"
        app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
        app:behavior_hideable="true"
        app:behavior_peekHeight = "0dp">
        <include layout="@layout/course_filter_page" />
    </androidx.core.widget.NestedScrollView>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>

And below is my onCreateVieHolder Item click

    public CoursesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell2, parent, false);
        final ViewHolder holder = new ViewHolder(view);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final Course currentCourse = mCourses.get(holder.getAdapterPosition());
                switchToCourseDetailsActivity(currentCourse);
            }
        });
        return holder;
    }

    private void switchToCourseDetailsActivity(Course currentCourse) {
        Intent intent = new Intent(mContext, CourseDetailsActivity .class);
        intent.putExtra("Course", currentCourse);
        mContext.startActivity(intent);
    }

And Below is my complete onBindViewHolder

public class CoursesAdapter extends RecyclerView.Adapter<CoursesAdapter.ViewHolder> {
private static final String TAG = "Courses List Adapter";
private static final String TAG2 = "Checker";

//vars
private Context mContext;
private ArrayList<Course> mCourses = new ArrayList<>();

Matcher matcher;

public CoursesAdapter(Context context, ArrayList<Course> courses) {
    mCourses = courses;
    mContext = context;

}


@NonNull
@Override
public CoursesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell2, parent, false);
    final ViewHolder holder = new ViewHolder(view);
    return holder;
     }

 private void switchToCourseDetailsActivity(Course currentCourse) {
    Intent intent = new Intent(mContext, CourseDetailsActivity .class);
    intent.putExtra("Course", currentCourse);
    mContext.startActivity(intent);
}


@Override
public void onBindViewHolder(@NonNull final CoursesAdapter.ViewHolder holder, final int position) {
    final Course currentCourse = mCourses.get(position);

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switchToCourseDetailsActivity(currentCourse);
        }
    });


    holder.name.setText(currentCourse.getTitle());
   // holder.coursePrice.setText(currentCourse.getPrice());
    holder.totalNumberOfRating.setText("( "+currentCourse.getTotalNumberRating()+" )");
    //holder.instructorName.setText("by "+currentCourse.getInstructor()+" "+currentCourse.getBiography());
    holder.starRating.setRating(currentCourse.getRating());
    holder.rating.setText((" "+currentCourse.getRating()+" "));

    if(currentCourse.getIs_bestseller().equals("yes")){
        holder.tvBestseller.setVisibility(View.VISIBLE);
    }else{
        holder.tvBestseller.setVisibility(View.GONE);
    }

    if(currentCourse.getCourseOverviewUrl()!=null && currentCourse.getCourseOverviewProvider()!=null && currentCourse.getCourseOverviewProvider().equals("youtube")){

        //Extract video id from url
        String pattern = "(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|\\/e\\/|watch\\?v%3D|watch\\?feature=player_embedded&v=|%2Fvideos%2F|embed%\u200C\u200B2F|youtu.be%2F|%2Fv%2F)[^#\\&\\?\\n]*";

        Pattern compiledPattern = Pattern.compile(pattern);
        matcher = compiledPattern.matcher(currentCourse.getCourseOverviewUrl()); //url is youtube url for which you want to extract the id.

        if (matcher.find()) {
                holder.play_video.setVisibility(View.VISIBLE);
                holder.play_video1.setVisibility(View.VISIBLE);

        } else{
            holder.play_video.setVisibility(View.GONE);
            holder.play_video1.setVisibility(View.GONE);
        }


    } else{
        holder.play_video.setVisibility(View.GONE);
        holder.play_video1.setVisibility(View.GONE);
    }


    holder.play_video.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final BottomSheetDialog dialog3 = new BottomSheetDialog(mContext);
            dialog3.setContentView(R.layout.bottom_videoplay);
            if(!dialog3.isShowing()) {
                dialog3.show();
            }
            dialog3.setCancelable(true);
            final WebView web_view = (WebView) dialog3.findViewById(R.id.youtube_web_view);
            final ProgressBar progressBar2 = (ProgressBar) dialog3.findViewById(R.id.progressBar2);
            final TextView tvTitle2 = (TextView) dialog3.findViewById(R.id.tvTitle2);
            final TextView tvEnroll = (TextView) dialog3.findViewById(R.id.tvEnroll);
            tvTitle2.setText(currentCourse.getTitle());

            tvEnroll.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    switchToCourseDetailsActivity(currentCourse);
                }
            });

            //String myVideoYoutubeId = "Wwy9aibAd54";
            String myVideoYoutubeId;
            WebSettings webSettings = web_view.getSettings();
            webSettings.setJavaScriptEnabled(true);
            webSettings.setLoadWithOverviewMode(true);
            webSettings.setUseWideViewPort(true);

            myVideoYoutubeId=matcher.group();
            web_view.loadUrl("https://www.youtube.com/embed/" + myVideoYoutubeId);


            web_view.setWebViewClient(new WebViewClient() {
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    return false;
                }
            });

            web_view.setWebViewClient(new WebViewClient() {

                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                    progressBar2.setVisibility(View.VISIBLE);
                }

                @Override
                public void onPageFinished(WebView view, String url) {
                    super.onPageFinished(view, url);
                    progressBar2.setVisibility(View.GONE);

                    //to enable autoplay ref:https://stackoverflow.com/questions/28039209/android-webview-youtube-embed-video-autoplay-not-working/45655979#45655979
                    long delta = 100;
                    long downTime = SystemClock.uptimeMillis();
                    float x = view.getLeft() + (view.getWidth()/2);
                    float y = view.getTop() + (view.getHeight()/2);

                    MotionEvent tapDownEvent = MotionEvent.obtain(downTime, downTime + delta, MotionEvent.ACTION_DOWN, x, y, 0);
                    tapDownEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
                    MotionEvent tapUpEvent = MotionEvent.obtain(downTime, downTime + delta + 2, MotionEvent.ACTION_UP, x, y, 0);
                    tapUpEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);

                    view.dispatchTouchEvent(tapDownEvent);
                    view.dispatchTouchEvent(tapUpEvent);

                }

            });


        }
    });

    holder.play_video1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            holder.play_video.performClick();
        }
    });

    if(currentCourse.getIs_mentor()!=null && currentCourse.getIs_mentor().equals("1")){
        holder.instructorName.setVisibility(View.VISIBLE);
        holder.tvMentor.setVisibility(View.GONE);

        if(currentCourse.getBiography()!=null) {
            holder.instructorName.setText("by " + currentCourse.getInstructor() + " " + currentCourse.getBiography());
        }else{
            holder.instructorName.setText("by " + currentCourse.getInstructor());
        }


    } else{
        //holder.tvMentor.setVisibility(View.GONE);
        holder.instructorName.setVisibility(View.GONE);
        holder.tvMentor.setVisibility(View.VISIBLE);

        if(currentCourse.getBiography()!=null) {
            holder.tvMentor.setText("by " + currentCourse.getInstructor() + " " + currentCourse.getBiography());
        } else{
            holder.tvMentor.setText("by " + currentCourse.getInstructor());
        }
    }


  if(currentCourse.getMain_price()!=null && !currentCourse.getPrice().equals("Free")){
        String  c_price = currentCourse.getPrice().substring(0, currentCourse.getPrice().length() - 1);
        Double main_price=Double.parseDouble(currentCourse.getMain_price());
        Double current_price=Double.parseDouble(c_price);

        if(current_price<main_price){
            holder.tvcompare.setVisibility(View.VISIBLE);
            holder.tvDiscountprice.setVisibility(View.VISIBLE);
            holder.tvDiscountprice.setText(Double.toString(main_price)+"Tk");

            Double diff=main_price-current_price;
            Double percent=diff*100/main_price;
            holder.tvcompare.setText(percent+"% OFF");

        }else{
            holder.tvDiscountprice.setVisibility(View.GONE);
            holder.tvcompare.setVisibility(View.GONE);
        }
    } else{
      holder.tvcompare.setVisibility(View.GONE);
      holder.tvDiscountprice.setVisibility(View.GONE);
  }

    if(!currentCourse.getPrice().equals("Free")) {
        String c_price = currentCourse.getPrice().substring(0, currentCourse.getPrice().length() - 1);
        holder.coursePrice.setText(c_price + "Tk");
    } else{
        holder.coursePrice.setText(currentCourse.getPrice());
    }



    if(currentCourse.getCourse_type()!=null){

        if(currentCourse.getCourse_type().equals("Course")){
            holder.tvCategory.setText("Lifetime Access");
            holder.image.setVisibility(View.VISIBLE);
            holder.play_video.setVisibility(View.VISIBLE);
            holder.monthly_couching.setVisibility(View.GONE);

            Glide.with(mContext)
                    .asBitmap()
                    .load(currentCourse.getThumbnail())
                    .into(holder.image);

        }

        if (currentCourse.getCourse_type().equals("MonthlyCouching")){
            holder.tvCategory.setText("Monthly Couching");
            holder.coursePrice.setText(holder.coursePrice.getText()+"/month");
            holder.image.setVisibility(View.GONE);
            holder.play_video.setVisibility(View.GONE);
            holder.monthly_couching.setVisibility(View.VISIBLE);
            Picasso.get().load(currentCourse.getThumbnail()).into(holder.image);
            Picasso.get().load(currentCourse.getThumbnail()).into(holder.image1);

            if(currentCourse.getOnline_classschedule()!=null){
                holder.layout_classschedule.setVisibility(View.VISIBLE);
                holder.tvClass_schedule.setText(currentCourse.getOnline_classschedule());
            } else{
                holder.layout_classschedule.setVisibility(View.GONE);
            }

        }

        if(currentCourse.getCourse_type().equals("FixedTermCouching")){

            holder.image.setVisibility(View.GONE);
            holder.play_video.setVisibility(View.GONE);
            holder.monthly_couching.setVisibility(View.VISIBLE);

            if(currentCourse.getDuration()!=null && currentCourse.getStart_date()!=null){

                long l = Long.parseLong(currentCourse.getStart_date());
                Date date = new Date(l);
                holder.tvCategory.setText(currentCourse.getDuration()+" Couching starting on "+date);
            }

            if(currentCourse.getOnline_classschedule()!=null){
                holder.layout_classschedule.setVisibility(View.VISIBLE);
                holder.tvClass_schedule.setText(currentCourse.getOnline_classschedule());
            } else{
                holder.layout_classschedule.setVisibility(View.GONE);
            }

        }

        if(currentCourse.getCourse_type().equals("Workshop")){

            holder.image.setVisibility(View.VISIBLE);
            holder.play_video.setVisibility(View.VISIBLE);
            holder.monthly_couching.setVisibility(View.GONE);

            if(currentCourse.getDuration()!=null && currentCourse.getStart_date()!=null){

                long l = Long.parseLong(currentCourse.getStart_date());
                Date date = new Date(l);
                holder.tvCategory.setText(currentCourse.getDuration()+" workshop starting on "+date);
            }
        }

    }


    if(currentCourse.getWeekly_class()!=null && currentCourse.getWeekly_class().equals("1")){
        holder.tvweekly_class.setVisibility(View.VISIBLE);

        if(currentCourse.getWeeklyonline_class()!=null && Integer.parseInt(currentCourse.getWeeklyonline_class())>0){
            holder.tvweekly_class.setText(holder.tvweekly_class.getText()+" "+currentCourse.getWeeklyonline_class());
        }

    } else{holder.tvweekly_class.setVisibility(View.GONE);}

    if(currentCourse.getWeekly_exam()!=null && currentCourse.getWeekly_exam().equals("1")){
        holder.tvweekly_exam.setVisibility(View.VISIBLE);

        if(currentCourse.getWeeklyonline_test()!=null && Integer.parseInt(currentCourse.getWeeklyonline_test())>0){
            holder.tvweekly_exam.setText(holder.tvweekly_exam.getText()+" "+currentCourse.getWeeklyonline_test());
        }

    } else{holder.tvweekly_exam.setVisibility(View.GONE);}

    if(currentCourse.getReview_class()!=null && currentCourse.getReview_class().equals("1")){
        holder.tvreview_class.setVisibility(View.VISIBLE);
    } else{holder.tvreview_class.setVisibility(View.GONE);}

    if(currentCourse.getCourse_upload()!=null && currentCourse.getCourse_upload().equals("1")){
        holder.tvcourse_upload.setVisibility(View.VISIBLE);
    } else{holder.tvcourse_upload.setVisibility(View.GONE);}

    if(currentCourse.getRecord_upload()!=null && currentCourse.getRecord_upload().equals("1")){
        holder.tvrecord_upload.setVisibility(View.VISIBLE);
    } else{holder.tvrecord_upload.setVisibility(View.GONE);}

    if(currentCourse.getCourse_type()!=null && currentCourse.getCourse_type().equals("FixedTermCouching") && currentCourse.getLifetime_access()!=null && currentCourse.getLifetime_access().equals("1")){
        holder.tvlifetime_access.setVisibility(View.VISIBLE);
    } else{holder.tvlifetime_access.setVisibility(View.GONE);}

}

@Override
public int getItemCount() {
    return mCourses.size();
}



public class ViewHolder extends RecyclerView.ViewHolder{

    ImageView image,image1,play_video,play_video1;
    TextView name;
    TextView coursePrice;
    TextView instructorName;
    TextView rating;
    TextView totalNumberOfRating;
    RatingBar starRating;
    TextView tvweekly_class,tvweekly_exam,tvreview_class,tvcourse_upload,tvrecord_upload,tvlifetime_access,tvCategory,tvDiscountprice,tvMentor,tvcompare,tvBestseller,tvClass_schedule;
    RelativeLayout monthly_couching;
    LinearLayout layout_classschedule;

    public ViewHolder(View itemView) {
        super(itemView);
        image = itemView.findViewById(R.id.courseThumbnail);
        image1 = itemView.findViewById(R.id.courseThumbnail1);
        name = itemView.findViewById(R.id.courseTitle);
        coursePrice = itemView.findViewById(R.id.tvcoursePrice);
        instructorName = itemView.findViewById(R.id.instructorName);
        rating = itemView.findViewById(R.id.numericRating);
        totalNumberOfRating = itemView.findViewById(R.id.totalNumberOfRatingByUsers);
        starRating = itemView.findViewById(R.id.starRating);
        tvweekly_class=itemView.findViewById(R.id.tvweekly_class);
        tvweekly_exam=itemView.findViewById(R.id.tvweekly_exam);
        tvreview_class=itemView.findViewById(R.id.tvreview_class);
        tvcourse_upload=itemView.findViewById(R.id.tvcourse_upload);
        tvrecord_upload=itemView.findViewById(R.id.tvrecord_upload);
        tvlifetime_access=itemView.findViewById(R.id.tvlifetime_access);
        tvCategory=itemView.findViewById(R.id.tvCategory);
        tvDiscountprice=itemView.findViewById(R.id.tvDiscountprice);
        tvMentor=itemView.findViewById(R.id.tvMentor);
        play_video=itemView.findViewById(R.id.play_video);
        play_video1=itemView.findViewById(R.id.play_video1);
        tvcompare=itemView.findViewById(R.id.tvcompare);
        tvBestseller=itemView.findViewById(R.id.tvBestseller);
        monthly_couching=itemView.findViewById(R.id.monthly_couching);
        tvClass_schedule=itemView.findViewById(R.id.tvClass_schedule);
        layout_classschedule=itemView.findViewById(R.id.layout_classschedule);

    }
}
}
Mithu
  • 665
  • 1
  • 8
  • 38

2 Answers2

1

RecyclerView reuses view holders to improve performance. You can also say it recycles view holders - this is where it gets its name from.

RecyclerView adapter will not create more view holders than it requires. The number of view holders can be roughly equal to:

// consider it pseudocode
viewHoldersCount = recyclerView.height / viewHolder.height + 1

So it will generate the number of view holders that fill the screen + 1 more item that is drawn off-screen (e.g. at the bottom of the recycler view) to smooth out scrolling animation and remove any glitches.

Following that: onCreateViewHolder is used only to create a view holder! Do not ever bind any data to a view holder from onCreateViewHolder.

If you have 100 of items in your adapter that you want to display but the screen of a device can display only 10 you will have 11 view holders that are reused when you scroll the list.

onBindViewHolder is called every time an item is going to be displayed - this is the place to attach data to your view holders.

public CoursesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell2, parent, false);
    return new ViewHolder(view);
}

public void onBindViewHolder(@NonNull final CoursesAdapter.ViewHolder holder, final int position) {
    final Course currentCourse = mCourses.get(position);

    holder.play_video.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
           // ...
        }
    }

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switchToCourseDetailsActivity(currentCourse);
        }
    });
}
Jenea Vranceanu
  • 4,530
  • 2
  • 18
  • 34
  • using this return ViewHolder(view); giving error as method call expected so i used this final ViewHolder holder = new ViewHolder(view); return holder; and item click method moved as you suggested. after this on first time load first item click works but last item remain same problem. again when i scroll to up then same problem for the first item as well . Another thing i notice is that item has an imageview on first time load for first item image not showing up, after scrolling it shows but clicking again works after second click – Mithu Sep 05 '20 at 04:37
  • @Mithu, about the error - I missed keyword `new`. That was the reason of the error. Answer updated. – Jenea Vranceanu Sep 05 '20 at 07:15
  • 1
    @Mithu, can you upload fully body of the `onBindViewHolder` implementation? – Jenea Vranceanu Sep 05 '20 at 07:19
  • edited my question and uploaded complete onBindViewHolder method – Mithu Sep 05 '20 at 08:25
  • I'm pretty sure `switchToCourseDetailsActivity` is getting called if you do not modify click listener of `itemView` somewhere else. Set a breakpoint on the line where `switchToCourseDetailsActivity` is getting called and debug your application to find the issue. – Jenea Vranceanu Sep 05 '20 at 11:14
  • but this method is being called on itemclick only – Mithu Sep 05 '20 at 11:18
0

At last I found a solution. My recyclerview layout has a nestedscrollview adding android:nestedScrollingEnabled="false" to my recyclerview solved my problem. I don't know why but it solved my problem

Mithu
  • 665
  • 1
  • 8
  • 38