tifyDataSetChange không hoạt động từ bộ điều hợp tùy chỉnh


126

Khi tôi sao chép lại của tôi ListView, tôi gọi một phương thức cụ thể từ của tôi Adapter.

Vấn đề :

Khi tôi gọi updateReceiptsListtừ của tôi Adapter, dữ liệu được làm mới, nhưng của tôi ListViewkhông phản ánh sự thay đổi.

Câu hỏi :

Tại sao tôi không ListViewhiển thị dữ liệu mới khi tôi gọi notifyDataSetChanged?

Bộ chuyển đổi :

public class ReceiptListAdapter extends BaseAdapter {

    public List<Receipt> receiptlist;
    private Context context;
    private LayoutInflater inflater;
    private DateHelpers dateH;

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
        context = mcontext;
        receiptlist = rl;
        Collections.reverse(receiptlist);
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dateH = new DateHelpers();
    }

    @Override
    public int getCount() {
        try {
            int size = receiptlist.size();
            return size;
        } catch(NullPointerException ex) {
            return 0;
        }
    }

    public void updateReceiptsList(List<Receipt> newlist) {
        receiptlist = newlist;
        this.notifyDataSetChanged();
    }

    @Override
    public Receipt getItem(int i) {
        return receiptlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return receiptlist.get(i).getReceiptId() ;
    }

    private String getPuntenString(Receipt r) {
        if(r.getPoints().equals("1")) {
            return "1 punt";
        }
        return r.getPoints()+" punten";
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;

        final Receipt receipt = receiptlist.get(position);
        ReceiptViewHolder receiptviewholder;
        Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
        Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");

        if (vi == null) { //convertview==null
            receiptviewholder = new ReceiptViewHolder();
            vi = inflater.inflate(R.layout.view_listitem_receipt, null);
            vi.setOnClickListener(null);
            vi.setOnLongClickListener(null);
            vi.setLongClickable(false);
            receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
            receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
            receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
            receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
            receiptviewholder.shop.setTypeface(tf_hn_bold);
            receiptviewholder.price.setTypeface(tf_hn_bold);
            vi.setTag(receiptviewholder);
        }else{//convertview is not null
            receiptviewholder = (ReceiptViewHolder)vi.getTag();
        }

        receiptviewholder.shop.setText(receipt.getShop());
        receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
        receiptviewholder.price.setText("€ "+receipt.getPrice());
        receiptviewholder.points.setText(getPuntenString(receipt));

        vi.setClickable(false);
        return vi;
    }

    public static class ReceiptViewHolder {
        public TextView shop;
        public TextView date;
        public TextView price;
        public TextView points;
    }

    public Object getFilter() {
        // XXX Auto-generated method stub
        return null;
    }

}

--BIÊN TẬP:

tìm thấy Giải pháp

Chỉ để có một số mã chức năng tôi làm bây giờ:

listview.setAdapter( new ReceiptListAdapter(activity,mcontext, -new dataset-);

Hoạt động, nhưng không phải cách nó được cho là hoạt động.


stackoverflow.com/a/4198569/2382964 , Xin chào Jasper, vui lòng tham khảo liên kết này ... điều này sẽ giúp bạn.
Tushar Pandey

thử các phương pháp khác nhưtifyItemInserted, thông báoItemRemoved, v.v.
Reejesh PK

Câu trả lời:


334

Thay đổi phương pháp của bạn từ

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist = newlist;
    this.notifyDataSetChanged();
}

Đến

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist.clear();
    receiptlist.addAll(newlist);
    this.notifyDataSetChanged();
}

Vì vậy, bạn giữ cùng một đối tượng như DataSet trong Bộ điều hợp của bạn.


Hãy xem xét việc có một đối tượng mẹ ReceiptListObjectthay vì một Listđối tượng, bạn có thể làm gì sau đó để giải quyết vấn đề này?
prom85

@ prom85 ArrayAdapters thậm chí có thể liên kết với các Đối tượng khác ngoài Danh sách hoặc Mảng không? Tôi không biết.
tolgap

đó là về một BaseAdaptervà bộ điều hợp này không biết nó được liên kết với dữ liệu nào ... vì vậy nếu tôi có một đối tượng tùy chỉnh và sử dụng các chức năng tùy chỉnh của đối tượng này (như custObject.getCount()custObject.getChildAt(int i)ví dụ) và tôi muốn trao đổi đối tượng này, thì đối tượng notifyDataSetChangednày không hoạt động ... dù sao, tôi nghĩ rằng vấn đề này không bao giờ xảy ra với mộtArrayAdapter
prom85

3
Bạn có thể giải thích tại sao phương pháp đầu tiên không hoạt động và phương pháp thứ hai hoạt động với BaseAdapter không?
Tooroop

1
bình luận như cám ơn hoặc +1 không được phép nhưng trên một số câu trả lời tôi thực sự thích để đưa ra một lời cảm ơn :)
Muhammad Saqib

24

Tôi có cùng một vấn đề, và tôi nhận ra điều đó. Khi chúng ta tạo bộ điều hợp và đặt nó thành listview, listview sẽ trỏ đến đối tượng ở đâu đó trong bộ nhớ mà bộ điều hợp giữ, dữ liệu trong đối tượng này sẽ hiển thị trong listview.

adapter = new CustomAdapter(data);
listview.setadapter(adapter);

nếu chúng ta tạo lại một đối tượng cho bộ điều hợp với một dữ liệu khác và thông báo lại ():

adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();

điều này sẽ không ảnh hưởng đến dữ liệu trong listview vì danh sách đang trỏ đến đối tượng khác, đối tượng này không biết bất kỳ điều gì về đối tượng mới trong bộ điều hợp, và InformDataSetChanged () không ảnh hưởng gì. Vì vậy, chúng ta nên thay đổi dữ liệu trong đối tượng và tránh tạo lại đối tượng mới cho bộ điều hợp


10
bạn đang tái tạo lại đối tượng adapter, nó không phải là hiệu quả
Alezis

2
@Alezis Tôi nghĩ đó chính là ý của Nhân.
Neeraj Sewani

17

Như tôi đã giải thích lý do đằng sau vấn đề này và cũng như cách xử lý nó trong một chuỗi câu trả lời khác Tại đây . Tôi vẫn đang chia sẻ bản tóm tắt giải pháp ở đây.

Một trong những lý do chính notifyDataSetChanged()sẽ không phù hợp với bạn - là

Bộ điều hợp của bạn mất tham chiếu đến danh sách của bạn .

Khi tạo và thêm một danh sách mới vào Adapter. Luôn tuân theo các nguyên tắc sau:

  1. Khởi tạo arrayListtrong khi khai báo nó trên toàn cầu.
  2. Thêm Danh sách vào bộ điều hợp trực tiếp mà không cần kiểm tra các giá trị rỗng và rỗng. Đặt bộ điều hợp vào danh sách trực tiếp (không kiểm tra bất kỳ điều kiện nào). Bộ điều hợp đảm bảo với bạn rằng bất cứ nơi nào bạn thực hiện thay đổi đối với dữ liệu của arrayListnó, nó sẽ xử lý nó, nhưng không bao giờ mất tham chiếu.
  3. Luôn thay đổi dữ liệu trong ArrayList bản thân (nếu dữ liệu của bạn là hoàn toàn mới hơn bạn có thể gọi adapter.clear()arrayList.clear()trước khi thực sự thêm dữ liệu vào danh sách) nhưng không đặt adapter ví dụ: Nếu các dữ liệu mới được phổ biến trong arrayListhơn là chỉ adapter.notifyDataSetChanged()

Hi vọng điêu nay co ich.


1
Cảm ơn! Mẹo ở # 2 đã hữu ích.
Cheruby

4

Có thể thử làm mới ListView của bạn:

receiptsListView.invalidate().

EDIT: Một suy nghĩ khác nảy ra trong đầu tôi. Chỉ dành cho bản ghi, hãy thử tắt bộ nhớ cache của chế độ xem danh sách:

<ListView
    ...
    android:scrollingCache="false"
    android:cacheColorHint="@android:color/transparent"
    ... />

Thật kỳ lạ, ý tưởng cuối cùng của tôi là gán lại bộ điều hợp cho chế độ xem danh sách sau khi dữ liệu thay đổi. Nhưng tôi cho rằng bạn cũng đã thử điều này.
Rafal Gałka

3

Tôi đã gặp vấn đề tương tự khi sử dụng ListAdapter

Tôi để Android Studio triển khai các phương pháp cho mình và đây là những gì tôi nhận được:

public class CustomAdapter implements ListAdapter {
    ...
    @Override
    public void registerDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

Vấn đề là các phương thức này không gọi các supertriển khai nên notifyDataSetChangekhông bao giờ được gọi.

Xóa các ghi đè này theo cách thủ công hoặc thêm siêu cuộc gọi và nó sẽ hoạt động trở lại.

@Override
public void registerDataSetObserver(DataSetObserver observer) {
    super.registerDataSetObserver(observer);
}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    super.unregisterDataSetObserver(observer);
}

2
class StudentAdapter extends BaseAdapter {
    ArrayList<LichHocDTO> studentList;

    private void capNhatDuLieu(ArrayList<LichHocDTO> list){
        this.studentList.clear();
        this.studentList.addAll(list);
        this.notifyDataSetChanged();
    }
}

Bạn co thể thử. Nó làm việc cho tôi



1

Nếu tình cờ bạn truy cập vào chủ đề này và tự hỏi tại sao adapter.invaidate()hoặc adapter.clear()các phương thức không có trong trường hợp của bạn thì có thể bởi vì bạn có thể đang sử dụng RecyclerView.Adapterthay vì BaseAdapterđược sử dụng bởi người hỏi câu hỏi này. Nếu xóa listhoặc arraylistkhông giải quyết vấn đề của bạn sau đó nó có thể xảy ra rằng bạn đang làm cho hai hoặc nhiều trường hợp của adaptercho ex .:

Hoạt động chủ yêu

...

adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);

...


SomeFragment

...

adapter = new CustomAdapter(newList);
adapter.notifyDataSetChanged();

...

Nếu trong trường hợp thứ hai, bạn đang mong đợi một sự thay đổi trong danh sách các chế độ xem tăng cao trong chế độ xem tái chế thì điều đó sẽ không xảy ra như trong lần thứ hai một phiên bản mới của adapterđược tạo mà không gắn với chế độ xem tái chế. Cài đặt notifyDataSetChangedtrong bộ điều hợp thứ hai sẽ không thay đổi nội dung của chế độ xem người tái chế. Vì vậy, hãy tạo một phiên bản mới của chế độ xem trình tái chế trong SomeFragment và đính kèm nó vào phiên bản mới của bộ điều hợp.

SomeFragment

...

recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);

...

Mặc dù, tôi không khuyên bạn nên tạo nhiều phiên bản của cùng một chế độ xem bộ điều hợp và trình tái chế.


0

Thêm mã này

runOnUiThread(new Runnable() { public void run() {
               adapter = new CustomAdapter(anotherdata);
            adapter.notifyDataSetChanged();
            }
        });

0

Tôi có cùng một vấn đề nhưng tôi chỉ cần hoàn thành nó !!

bạn nên thay đổi thành

public class ReceiptListAdapter extends BaseAdapter {

    public List<Receipt> receiptlist;
    private Context context;
    private LayoutInflater inflater;
    private DateHelpers dateH;
    private List<ReceiptViewHolder> receiptviewlist;

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
        context = mcontext;
        receiptlist = rl;
        receiptviewlist = new ArrayList<>();
        receiptviewlist.clear();
        for(int i = 0; i < receiptlist.size(); i++){
          ReceiptViewHolder receiptviewholder = new ReceiptViewHolder();
          receiptviewlist.add(receiptviewholder);
        }
        Collections.reverse(receiptlist);
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dateH = new DateHelpers();
    }

    @Override
    public int getCount() {
        try {
            int size = receiptlist.size();
            return size;
        } catch(NullPointerException ex) {
            return 0;
        }
    }

    public void updateReceiptsList(List<Receipt> newlist) {
        receiptlist = newlist;
        this.notifyDataSetChanged();
    }

    @Override
    public Receipt getItem(int i) {
        return receiptlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return receiptlist.get(i).getReceiptId() ;
    }

    private String getPuntenString(Receipt r) {
        if(r.getPoints().equals("1")) {
            return "1 punt";
        }
        return r.getPoints()+" punten";
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;

        final Receipt receipt = receiptlist.get(position);
        ReceiptViewHolder receiptviewholder;
        Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
        Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");

        if (vi == null) { //convertview==null
            ReceiptViewHolder receiptviewholder = receiptviewlist.get(position);
            vi = inflater.inflate(R.layout.view_listitem_receipt, null);
            vi.setOnClickListener(null);
            vi.setOnLongClickListener(null);
            vi.setLongClickable(false);
            receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
            receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
            receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
            receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
            receiptviewholder.shop.setTypeface(tf_hn_bold);
            receiptviewholder.price.setTypeface(tf_hn_bold);
            vi.setTag(receiptviewholder);
        }else{//convertview is not null
            receiptviewholder = (ReceiptViewHolder)vi.getTag();
        }

        receiptviewholder.shop.setText(receipt.getShop());
        receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
        receiptviewholder.price.setText("€ "+receipt.getPrice());
        receiptviewholder.points.setText(getPuntenString(receipt));

        vi.setClickable(false);
        return vi;
    }

    public static class ReceiptViewHolder {
        public TextView shop;
        public TextView date;
        public TextView price;
        public TextView points;
    }

    public Object getFilter() {
        // XXX Auto-generated method stub
        return null;
    }

}

0

Trường hợp của tôi khác nhưng nó có thể giống trường hợp của những người khác

đối với những người vẫn không thể tìm thấy giải pháp và đã thử mọi thứ ở trên, nếu bạn đang sử dụng bộ điều hợp bên trong phân đoạn thì lý do nó không hoạt động fragment could be recreating so the adapter is recreating everytime the fragment recreate

bạn nên xác minh xem bộ điều hợp và danh sách đối tượng có rỗng không trước khi khởi tạo

if(adapter == null){
  adapter = new CustomListAdapter(...);
}
...

if(objects == null){
  objects = new ArrayList<>();
}

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.