5

Tại sao ngoại lệ thực hiện khi tôi xóa một số mục trong RecyclerView bằng cách sử dụng vòng lặp? Tôi đã sử dụng Collentions.synchronizedMap trong bộ điều hợp và 'phương pháp deleteItem' sử dụng đồng bộ hóa quá (phương pháp trong phân đoạn).RecyclerView IndexOutOfBoundsException

public void elementController(JsonObject jsonObject , String type) { 
    if (jsonObject == null || type == null) { 
     return; 
    } 

    int position =0 , resultPosition =0; 
    if (type.equals("update") || type.equals("delete")) { 

     String id = jsonObject.get(ELEMENT_ID).getAsString(); 
     Map<String , Element> map = gridFragment.getMap(); 

     synchronized (map) { 
      for (String s : map.keySet()) { 
       if (s.equals(id)) { 
        resultPosition = position; 
       } else { 
        position++; 
       } 
      } 
     } 
    } 

    if(position-1 > gridFragment.getmAdapter().getData().size() || position <0) { 
     return; 
    } 
    switch (type) { 
     case "add": 
      if (gridFragment.addElement(MyJsonParser.ElementParse(jsonObject),0)){ 
       LogUtils.logDebug(TAG,"add end"); 
      } 
      break; 
     case "update": 
      if(gridFragment.updateElement(updateParser(jsonObject),resultPosition)){ 
       LogUtils.logDebug(TAG,"update end"); 
      } 
      break; 
     case "delete": 
      if(gridFragment.deleteElement(jsonObject.get(ELEMENT_ID).getAsString(),resultPosition)){ 
       LogUtils.logDebug(TAG,"delete end"); 
      } 
      break; 
    } 
} 

public boolean deleteElement(final String id , final int position){ 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      getActivity().runOnUiThread(new Runnable(){ 
       @Override 
       public void run() { 
        synchronized (map) { 
         map.remove(id); 
         mAdapter.setData(map); 
         mAdapter.notifyItemRemoved(position); 
        } 
       } 
      }); 
     } 
    }).start(); 

    return true; 
} 

lỗi My Log:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 0(offset:0).state:4 
     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3382) 
     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3340) 
     at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1810) 
     at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:356) 
     at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1269) 
     at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:523) 
     at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:151) 
     at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1942) 
     at android.support.v7.widget.RecyclerView.resumeRequestLayout(RecyclerView.java:1171) 
     at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:167) 
     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761) 
     at android.view.Choreographer.doCallbacks(Choreographer.java:574) 
     at android.view.Choreographer.doFrame(Choreographer.java:543) 
     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747) 
     at android.os.Handler.handleCallback(Handler.java:733) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:212) 
     at android.app.ActivityThread.main(ActivityThread.java:5137) 
     at java.lang.reflect.Method.invokeNative(Native Method) 
     at java.lang.reflect.Method.invoke(Method.java:515) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718) 
     at dalvik.system.NativeStart.main(Native Method) 

thiết bị không tìm thấy

+1

mã đầu tiên không có ý nghĩa, bạn lặp lại và chỉ nhận được một vị trí từ vòng lặp. không có điều kiện break –

+0

Bạn đang thiết lập dữ liệu mAdapter của bạn sau khi loại bỏ các mục, và sau đó cố gắng để loại bỏ các vị trí được chỉ định, mà trong trường hợp này không tồn tại. –

+0

tất cả mã đầu tiên được gọi bằng dịch vụ (tôi sử dụng mạng ổ cắm với máy chủ). tôi có jsonarray từ máy chủ và gửi jsonobjects đến mã đầu tiên trong jsonarray bởi cho vòng lặp. vì vậy nó là vòng lặp đầu tiên. tôi đoán jsonobject thứ hai đã được sended bởi params để mã đầu tiên trước khi kết thúc mã đầu tiên. –

Trả lời

3

Chưa đọc mã của bạn vì tôi không quen với các lớp bạn sử dụng nhưng tôi biết cách khắc phục sự cố này. Vấn đề xảy ra khi các yếu tố hàng xóa không phải là cuối cùng vì sự khác biệt chỉ mục giữa chỉ số datalist (ArrayList của bạn để lưu trữ dữ liệu) và tham số final int position trong mehod onBindViewHolder. Hãy để tôi giải thích vấn đề này một cách đồ họa:

enter image description here

giả sử chúng ta có một RecyclerView với ba hàng và chúng tôi xóa dòng thứ 3, tại index datalist 2, (lưu ý xóa một không phải là yếu tố cuối cùng) sau khi loại bỏ, chỉ số dữ liệu cho phần tử cuối cùng giảm 3 từ 2 tuy nhiên, final int position vẫn truy xuất vị trí của nó là 3 và điều đó gây ra sự cố. Vì vậy, sau khi xóa, bạn không thể sử dụng final int position làm chỉ mục của phần tử được xóa khỏi trình dữ liệu.

Để khắc phục điều này, hãy giới thiệu int shift=0 và trong vòng lặp while, try xóa mục thứ ba tại (vị trí dịch chuyển) và nếu không thành công (trong trường hợp của tôi) sẽ thay đổi và thử loại bỏ nó một lần nữa xảy ra.

public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 

    ... 

     holder.removeButton.setOnClickListener(new View.OnClickListener(){ //button used to remove rows 
        @Override 
        public void onClick(View view) { 
         if (position == dataList.size() - 1) { // if last element is deleted, no need to shift 
          dataList.remove(position); 
          notifyItemRemoved(position); 
         } else { // if the element deleted is not the last one 
          int shift=1; // not zero, shift=0 is the case where position == dataList.size() - 1, which is already checked above 
          while (true) { 
           try { 
            dataList.remove(position-shift); 
            notifyItemRemoved(position); 
            break; 
           } catch (IndexOutOfBoundsException e) { // if fails, increment the shift and try again 
            shift++; 
           } 
          } 
         } 
        } 
       }); 
    ... 
    } 
3
mAdapter.notifyItemRemoved(position); 

này chỉ thông báo cho các quan sát viên được lắng nghe những thay đổi bố trí.

Thay vào đó, hãy thử gọi:

mAdpater.nofityDataChanged() 
+7

Đừng gọi nofityDataChanged() trừ khi bạn thay đổi toàn bộ nội dung danh sách nếu không tất cả các hoạt ảnh sẽ bị hủy vì Item được rebinded. Vui lòng xem câu trả lời của tôi và tại FlexibleAdapter của tôi cho tất cả các phương thức * notify() * – Davidea

2

Vâng, điều đó xảy ra vì truy cập đồng thời. Tôi đã gặp nó. Dễ dàng sửa lỗi với Iterator hoặc với mẹo hay: bạn bắt đầu xóa khỏi mục cuối cùng. Tuy nhiên lệnh Z-A với Iterator là tốt hơn.

Gần đây tôi đã cải thiện và tạo một FlexibleAdapter sử dụng giải pháp này. Xin vui lòng, cũng có một cái nhìn vào mô tả và ví dụ làm việc đầy đủ: https://github.com/davideas/FlexibleAdapter

0

Tôi sử dụng trình xử lý và phương thức gọi trong bộ điều hợp.

List.delete (position); 
notifyitemremoved (position); 
notifydatachanged(); 
+5

Thay đổi dữ liệu cuộc gọi buộc bộ điều hợp phải rebind tất cả các phần tử làm cho cuộc gọi đến itemremoved vô nghĩa. – ntlv

Các vấn đề liên quan