【问题标题】:Android RecyclerView First and Last Item click works after Double click on First load双击第一次加载后,Android RecyclerView 第一个和最后一个项目点击有效
【发布时间】:2020-12-23 16:33:28
【问题描述】:

我有一个recyclerview。它在onCreateViewHolder 方法中有项目点击事件,在onBindViewHolder 方法中有一个imageview 点击事件。令人惊讶的是,当 recyclerview 第一次加载first and last item click 在第二次点击后工作,然后在每次点击后如果它没有滚动。再次当我滚动 recyclerview 时,第一个和最后一个项目也会发生同样的情况,就像第一次加载一样。我不知道是什么问题

下面是我的recyclerview布局@+id/recyclerViewForFilteredCourses是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>

下面是我的 onCreateVieHolder 项目点击

    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);
    }

下面是我完整的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);

    }
}
}

【问题讨论】:

    标签: java android android-recyclerview


    【解决方案1】:

    我终于找到了解决办法。我的 recyclerview 布局有一个nestedscrollview 将 android:nestedScrollingEnabled="false" 添加到我的recyclerview 解决了我的问题。我不知道为什么,但它解决了我的问题

    【讨论】:

      【解决方案2】:

      RecyclerView 重用视图持有者以提高性能。你也可以说它recycles视图持有者——这就是它得名的地方。

      RecyclerView 适配器不会创建比它需要的更多的视图持有者。视图持有者的数量可以大致等于:

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

      因此它将生成填满屏幕的视图持有者数量 + 1 个在屏幕外绘制的项目(例如在回收器视图的底部),以平滑滚动动画并消除任何故障。

      以下:onCreateViewHolder 仅用于创建视图持有者! 永远不要将任何数据绑定到来自onCreateViewHolder 的视图持有者。

      如果您的适配器中有 100 个要显示的项目,但设备的屏幕只能显示 10 个,那么您将有 11 个视图持有者在您滚动列表时重复使用。

      onBindViewHolder 会在每次显示项目时调用 - 这是将数据附加到视图持有者的地方。

      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);
              }
          });
      }
      

      【讨论】:

      • 使用这个返回 ViewHolder(view);按照预期的方法调用给出错误,所以我使用了这个最终的 ViewHolder holder = new ViewHolder(view);退货持有人;并按照您的建议移动了项目单击方法。在此之后第一次加载第一个项目点击工作,但最后一个项目仍然存在同样的问题。当我再次向上滚动时,第一项也出现同样的问题。我注意到的另一件事是该项目在第一次加载时有一个图像视图,因为第一个项目图像没有显示,在滚动后它显示,但在第二次点击后再次点击可以工作
      • @Mithu,关于错误 - 我错过了关键字 new。这就是错误的原因。答案已更新。
      • @Mithu,你能上传完整的onBindViewHolder 实现吗?
      • 编辑了我的问题并上传了完整的 onBindViewHolder 方法
      • 如果您不修改 itemView 的点击侦听器,我很确定 switchToCourseDetailsActivity 会被调用。在调用switchToCourseDetailsActivity 的行上设置断点并调试您的应用程序以找到问题。
      猜你喜欢
      • 1970-01-01
      • 2011-11-17
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      相关资源
      最近更新 更多