Recyclerview Thay đổi các mục trong khi cuộn


79

Tôi có RecyclerView. Mỗi hàng có một nút phát, chế độ xem văn bản và Thanh tiến trình. Khi nhấp vào nút phát phải phát âm thanh từ thẻ nhớ của tôi và phải tiến trình Thanh tiến trình Vấn đề là khi tôi cuộn xuống chế độ xem tái chế, thay đổi Thanh tiến trình ở hàng tiếp theo. có nghĩa là tôi có thể phù hợp với 5 mục trên màn hình cùng một lúc. Khi tôi cuộn đến thanh tìm kiếm hàng thứ 6, thứ 6 thay đổi đột ngột.

public class ListAdapter extends RecyclerView.Adapter {

    private List<Historyitem> stethitems;
    public Context mContext;
    public Activity activity;
    public Handler mHandler;

    static MediaPlayer mPlayer;
    static Timer mTimer;

    public ListAdapter(Activity activity,Context mContext,List<Historyitem> stethitems) {
        this.stethitems = stethitems;
        this.mContext = mContext;
        this.activity = activity;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View rootView = LayoutInflater.
                from(mContext).inflate(R.layout.stethoscopeadapteritem, null, false);
        RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        rootView.setLayoutParams(lp);
        mHandler = new Handler();
        return new MyViewHolder(rootView);
    }

    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {

        final Historyitem dataItem = stethitems.get(position);
        final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
        myViewHolder.progressplay.setProgress(0);
        myViewHolder.stethdatetime.setText(dataItem.getReported_Time());
        myViewHolder.stethhosname.setText(dataItem.getdiv());

        if(dataItem.getPatient_Attribute().replaceAll(" ","").equals("")){
            myViewHolder.stethdoctorname.setText(dataItem.getunit());
        } else {
            myViewHolder.stethdoctorname.setText(dataItem.getPatient_Attribute());
        }

        myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                   FileDownload(dataItem.getmsg(),
                            myViewHolder.progressplay);

            }
        });
    }

    @Override
    public int getItemCount() {

        return stethitems.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        final CustomTextRegular stethdatetime;
        final CustomTextView stethhosname;
        final CustomTextBold stethdoctorname;
        final ImageButton stethstreamplay;
        final NumberProgressBar progressplay;

        public MyViewHolder(View itemView) {
            super(itemView);

            stethdatetime = (CustomTextRegular)
                    itemView.findViewById(R.id.stethdatetime);
            stethhosname = (CustomTextView)
                    itemView.findViewById(R.id.stethhosname);
            stethdoctorname = (CustomTextBold)
                    itemView.findViewById(R.id.stethdoctorname);
            stethstreamplay = (ImageButton)
                    itemView.findViewById(R.id.stethstreamplay);
            progressplay= (NumberProgressBar)
                    itemView.findViewById(R.id.progressplay);


        }
    }
    public void  FileDownload(final String downloadpath,

                                     final NumberProgressBar progressplay) {

        new AsyncTask<NumberProgressBar, Integer, NumberProgressBar>() {
            NumberProgressBar progress;
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                try {
                    if(mPlayer!=null){
                        mPlayer.stop();
                    }
                }catch (Exception e){
                }
                try {
                    if(mTimer != null){
                        mTimer.purge();
                        mTimer.cancel();
                    }
                }catch (Exception e){
                }
            }

            @Override
            protected NumberProgressBar doInBackground(NumberProgressBar... params) {
                int count;
                progress = progressplay;
                try {

                    final List<NameValuePair> list = new ArrayList<NameValuePair>();
                    list.add(new BasicNameValuePair("pid",id));

                    URL url = new URL(Config.requestfiledownload + "?path=" +
                            downloadpath);
                    URLConnection connection = url.openConnection();
                    connection.connect();

                    int lenghtOfFile = connection.getContentLength();
                    // download the file
                    InputStream input = new BufferedInputStream(url.openStream());
                    OutputStream output = new FileOutputStream(Environment.getExternalStorageDirectory() +
                            "record.wav");
                    byte data[] = new byte[1024];
                    long total = 0;
                    while ((count = input.read(data)) != -1) {
                        total += count;
                        // publishing the progress....
                        publishProgress((int) (total * 100 / lenghtOfFile));
                        output.write(data, 0, count);
                    }
                    output.flush();
                    output.close();
                    input.close();
                } catch (Exception e) {

                }
                return progress;
            }
            @Override
            protected void onPostExecute(final NumberProgressBar numberProgressBar) {
                super.onPostExecute(numberProgressBar);

                        try {
                            StartMediaPlayer(numberProgressBar);
                        } catch (Exception e){
                            e.printStackTrace();
                        }

            }
        }.execute();
    }

    public void StartMediaPlayer(final NumberProgressBar progressbar){
        Uri playuri = Uri.parse("file:///sdcard/record.wav");
        mPlayer = new MediaPlayer();
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.reset();
        try {
            mPlayer.setDataSource(mContext, playuri);
        } catch (IllegalArgumentException e) {

        } catch (SecurityException e) {

        } catch (IllegalStateException e) {

        } catch (Exception e) {

        }
        try {
            mPlayer.prepare();
        } catch (Exception e) {

        }

        mPlayer.start();
        progressbar.setMax(mPlayer.getDuration());
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if(mPlayer!=null) {
                    mPlayer.release();
                    progressbar.setProgress(0);
                }
                if(mTimer != null){
                    mTimer.purge();
                    mTimer.cancel();
                }
            }
        });
        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        progressbar.setProgress(mPlayer.getCurrentPosition());
                    }
                });
            }
        },0,500);
    }}

Như câu trả lời của Tôi, đang giúp nhiều người, Bạn có thể vui lòng chấp nhận câu trả lời của tôi. Cảm ơn
Surendar D

Câu trả lời:


234

Hãy thử cái này

  1. Nếu bạn đang sử dụng ListView- ghi đè các phương pháp sau.

     @Override
     public int getViewTypeCount() {    
         return getCount();
     }
    
     @Override
     public int getItemViewType(int position) {    
         return position;
     }
    
  2. Nếu bạn đang sử dụng RecyclerView- chỉ ghi đè getItemViewType()phương pháp.

     @Override
     public int getItemViewType(int position) {    
         return position;
     }
    

5
giải pháp tuyệt vời .. đã cứu một ngày của tôi
Däñish Shärmà

1
Câu trả lời tốt nhất bro.really giúp
Nitheesh KP

2
OMG nó hoạt động hoàn hảo. :) Câu trả lời này phải được chấp nhận
Ajay Shrestha

4
Tại sao getItemViewTypelại trở về position?? Tò mò về câu trả lời này.
Jimit Patel

10
Cách tiếp cận này có thể ảnh hưởng đến hiệu suất, đặc biệt là khi có một danh sách lớn các mục: Một lợi thế lớn của RecyclerView là nó sử dụng lại các phiên bản ViewHolder và hệ thống phân cấp chế độ xem tương ứng. Vì vậy, khi người dùng cuộn và các mục mới được hiển thị thay vì tạo các chế độ xem mới, các ViewHolders trước đó không hiển thị nữa sẽ được tái chế và liên kết với các mục mới hiển thị. Nhưng bằng cách trả về vị trí là loại, RecyclerView sẽ xử lý từng ViewHolder là không thể sử dụng lại cho một mục mới vì nó có một loại khác. Vì vậy, các "tính năng tái chế" của RecyclerView về cơ bản là vô hiệu hóa bằng cách làm này
pakat

60

Thêm setHasStableIds(true);phương thức khởi tạo bộ điều hợp của bạn và Ghi đè hai phương thức này trong bộ điều hợp. Nó cũng hoạt động nếu bất kỳ ai sử dụng RecyclerViewbên trong a ViewPagercũng bên trong a NestedScrollView.

@Override
public long getItemId(int position) {
            return position;
}

@Override
public int getItemViewType(int position) {
       return position;
}

1
Đây là câu trả lời tốt nhất cho tôi và RecyclerView của tôi. Chỉ ghi đè "getItemViewType" loại bỏ một số ngẫu nhiên đối với Chế độ xem tái chế của tôi (chỉ khi cuộn xuống, đi lên trên các vị trí, nhưng không hoạt động khi lùi lại). Việc triển khai cả ghi đè "getItemId" và "setHasStableIds (true)" đều thực hiện công việc một cách hoàn hảo, cả cuộn xuống và cuộn lên.
Alessandro Iudicone

8
Nhưng vấn đề là hiện tại khi tôi có getItemViewType trả về các loại viewType khác nhau, không chỉ vị trí regural. Có ai biết nóng để giải quyết điều này?
RadoVidjen

Cảm ơn, tôi đã phải vật lộn với một vấn đề tương tự trong cả ngày với đầu vào văn bản có thể thay đổi giá trị một cách ngẫu nhiên. Bạn là một vị cứu tinh.
Geoff

tôi luôn trở lại ở đây
Acauã Pitta

29

Như tên của nó, các khung nhìn trong a RecyclerViewđược tái chế khi bạn cuộn xuống. Điều này có nghĩa là bạn cần giữ trạng thái của từng mục trong mô hình hỗ trợ của bạn, trong trường hợp này sẽ là a Historyitemvà khôi phục nó trong mô hình của bạn onBindViewHolder.

1) Tạo vị trí, tối đa và bất kỳ biến nào khác mà bạn cần để lưu trạng thái của ProgressBar trong mô hình của mình.

2) Đặt trạng thái của bạn ProgressBardựa trên dữ liệu trong mô hình hỗ trợ của bạn; khi nhấp chuột, chuyển vị trí của mục cho FileDownload/ StartMediaPlayercác phương pháp của bạn .

public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
    final Historyitem dataItem = stethitems.get(position);
    final MyViewHolder myViewHolder = (MyViewHolder) viewHolder;
    myViewHolder.progressplay.setMax(dataItem.getMax());
    myViewHolder.progressplay.setProgress(dataItem.getPosition());
    ...
    myViewHolder.stethstreamplay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
               FileDownload(dataItem.getmsg(), position);
        }
    });

3) Cập nhật thanh tiến trình bằng cách cập nhật mô hình hỗ trợ và thông báo rằng nó đã được thay đổi.

stethitems.get(position).setPosition(mPlayer.getCurrentPosition());
notifyItemChanged(position);

12

Tôi đã gặp phải vấn đề tương tự trong khi tôi đang cố gắng triển khai chế độ xem lại có chứa biên tập và hộp kiểm dưới dạng các phần tử hàng. Tôi đã giải quyết vấn đề thay đổi giá trị cuộn chỉ bằng cách thêm hai dòng sau trong lớp bộ điều hợp.

@Override
public long getItemId(int position) {
    return position;
}

@Override
public int getItemViewType(int position) {
    return position;
}

Tôi hy vọng nó sẽ là một giải pháp khả thi. Cảm ơn


5

recyclerview.setItemViewCacheSize(YourList.size());


Thông thường, đó không phải là một cách tốt để lưu danh sách của bạn vào bộ nhớ đệm, tuy nhiên, hôm nay tôi đã có một chế độ xem tái chế nhỏ nên điều này đã tiết kiệm ngày của tôi. Cảm ơn bạn rất nhiều
Okan Serdaroğlu

3

Đặt recylerViewtrong NestedScroll Viewcủa bạn XMLvà thêm tài sản nestedScrollingEnabled = false.

Và trên bộ điều hợp của bạn onBindViewHolderthêm dòng này

final MyViewHolder viewHolder = (MyViewHolder)holder;

Sử dụng viewHolderđối tượng này với chế độ xem của bạn để setTexthoặc thực hiện bất kỳ loại sự kiện nhấp chuột nào.

ví dụ viewHolder.txtSubject.setText("Example");


Đặt recylerView trong Chế độ xem NestedScroll trong XML của bạn và thêm thuộc tính nestedScrollingEnabled = false. nhờ điều này giúp tôi :)
Sachin Solanki

2

Khi chúng tôi thay đổi RecyclerViewcác mục một cách động (tức là khi thay đổi màu nền của một RecyclerViewmục cụ thể ), nó có thể thay đổi hình thức của các mục theo những cách không mong muốn khi cuộn do bản chất của cách RecyclerViewsử dụng lại các mục của nó.

Tuy nhiên, để tránh điều đó, có thể sử dụng android.support.v4.widget.NestedScrollViewquấn quanh RecyclerViewvà để NestedScrollViewtay cầm cuộn.

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

   </LinearLayout>
</android.support.v4.widget.NestedScrollView>

Và sau đó trong mã, bạn có thể tắt tính năng cuộn lồng nhau để cuộn RecyclerViewtrơn tru hơn bằng cách chỉ cho phép NestedScrollViewcuộn để xử lý.

ViewCompat.setNestedScrollingEnabled(recyclerView, false);

1

Nếu chế độ xem lại ViewHolder của bạn có nhiều logic hơn hoặc có một chế độ xem khác thì bạn nên thử:

 **order_recyclerView.setItemViewCacheSize(x);**

trong đó x là kích thước của danh sách. Những điều trên hiệu quả với tôi, tôi hy vọng nó cũng hiệu quả với bạn.


cái này làm việc cho tôi cảm ơn
Sujeet Kumar

0

Tôi đã gặp vấn đề tương tự khi xử lý rất nhiều dữ liệu, nó hoạt động với 5 vì nó hiển thị năm phần tử hiển thị trên màn hình nhưng điều đó mang lại cho prob có nhiều phần tử hơn. Vấn đề là ..

Đôi khi RecyclerView và listView chỉ bỏ qua việc điền dữ liệu. Trong trường hợp chức năng ràng buộc RecyclerView bị bỏ qua khi cuộn nhưng khi bạn thử và gỡ lỗi bộ điều hợp RecyclerView, nó sẽ hoạt động tốt vì nó sẽ gọi onBind mọi lúc, bạn cũng có thể xem chế độ xem của nhà phát triển google chính thức Thế giới của listView . Khoảng 20 phút -30 phút, họ sẽ giải thích rằng bạn không bao giờ có thể giả định rằng getView theo vị trí sẽ được gọi mọi lúc.

vì vậy, tôi sẽ đề nghị sử dụng

RecyclerView DataBinder được tạo bởi satorufujiwara.

hoặc là

RecyclerView MultipleViewTypes Binder được tạo bởi yqritc.

Đây là những chất kết dính khác có sẵn nếu bạn thấy chúng dễ sử dụng.

Đây là cách để xử lý các Loại MultipleView hoặc nếu bạn đang sử dụng lượng lớn dữ liệu. Những chất kết dính này có thể giúp bạn chỉ cần đọc kỹ tài liệu là sẽ khắc phục được, bình an !!


0

Tại sao bạn không thử như thế này,

    HashMap<String, Integer> progressHashMap = new HashMap<>();

    //...
    if(!progressHashMap.containsKey(downloadpath)){
        progressHashMap.put(downloadpath, mPlayer.getCurrentPosition());
    }

    progressbar.setProgress(progressHashMap.get(downloadpath));

0

thử cái này

@Override public void smoothScrollToPosition(RecyclerView    recyclerView, RecyclerView.State state,
       int position) {    LinearSmoothScroller linearSmoothScroller =
           new LinearSmoothScroller(recyclerView.getContext()) {
               @Override
               public PointF computeScrollVectorForPosition(int targetPosition) {
                   return LinearLayoutManager.this
                           .computeScrollVectorForPosition(targetPosition);
               }
           };    linearSmoothScroller.setTargetPosition(position);    startSmoothScroll(linearSmoothScroller); }

cũng xem cái này


0

Dòng này thay đổi tiến trình thành 0 trên mỗi ràng buộc

myViewHolder.progressplay.setProgress(0);

Lưu trạng thái của nó ở đâu đó sau đó tải nó trong cùng một dòng này.


0

Ghi đè phương thức getItemViewType trong bộ điều hợp. sử dụng kotlin

override fun getItemViewType(position: Int): Int {
    return position
}

-2

Đây là hành vi mong đợi của RecyclerView. Vì chế độ xem được tái chế, các mặt hàng của bạn có thể lọt vào các chế độ xem ngẫu nhiên. Để khắc phục điều này, bạn phải chỉ định mục nào được đưa vào loại chế độ xem nào của chính mình. Thông tin này có thể được giữ trong SparseBooleanArray. những gì bạn có thể làm là tạo SparseBooleanArray trong bộ điều hợp của bạn như thế này

SparseBooleanArray selectedItems = new SparseBooleanArray();

bất cứ khi nào chế độ xem của bạn thay đổi, hãy làm:

selectedItems.put(viewItemIndex,true);

Bây giờ trong onBindViewHolder của bạn làm

 if(selectedItems.get(position, false)){
    //set progress bar of related to the view to desired position
    }
    else {
        //do the default
    }

Đây là điều cơ bản để giải quyết vấn đề của bạn. Bạn có thể điều chỉnh logic này cho bất kỳ loại vấn đề tương tự nào trong RecyclerView.


Làm thế nào để thiết lập viewItemIndex của view
Arya

Đó là mục trong danh sách bộ điều hợp của bạn. Bạn có thể sử dụng getAdapterPostion hoặc stethitems.get(position)như trong mã của bạn.
rockfight

Tôi vẫn đang đối mặt với cùng một vấn đề. khi tôi cuộn xuống chế độ xem tái chế, hãy thay đổi Thanh tiến trình ở hàng tiếp theo.
Arya

Nó không đi vào phần khác.
Arya

à xin lỗi, đổi if(selectedItems.get(position, true))thành if(selectedItems.get(position, false)). Tôi sẽ chỉnh sửa câu trả lời ban đầu.
rockfight

-2

Tôi đã gặp vấn đề tương tự và đã tìm kiếm rất nhiều câu trả lời đúng. Về cơ bản, nó là một thiết kế của chế độ xem tái chế mà nó cập nhật chế độ xem trên cuộn vì nó làm mới chế độ xem.

Vì vậy, tất cả những gì bạn cần làm là vào thời gian ràng buộc, hãy nói với nó không làm mới nó.

Đây là cách onBindViewHolder của bạn trông như thế nào

@Override
@SuppressWarnings("unchecked")
public void onBindViewHolder(final BaseViewHolder holder, final int position) {
    holder.bind(mList.get(position));

    // This is the mighty fix of the issue i was having
    // where recycler view was updating the items on scroll.
    holder.setIsRecyclable(false);
}

1
Nó đánh bại toàn bộ mục đích của việc sử dụng "RECYCLER" view
Alex
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.