web-dev-qa-db-ja.com

Android:リストビューのコンテンツを更新する方法は?

私のListViewBaseAdapterの拡張子を使用していますが、正しく更新できません。更新すると、スクロールイベントが発生するまで、古いデータが新しいデータの上に描画されているように見えます。古い行は新しい行の上に描画されますが、スクロールを開始すると古い行は消えます。

invalidateViews()notifyDataSetChanged()、およびnotifyDataSetInvalidated()を呼び出してみました。私のコードは次のようになります:

private void updateData()
{
   List<DataItems> newList = getNewList();

   MyAdapter adapter = new MyAdapter(getContext());
   //my adapter holds an internal list of DataItems
   adapter.setList(newList);
   mList.setAdapter(adapter);
   adapter.notifyDataSetChanged();
   mList.invalidateViews();
}
38
ab11

まだ問題がある人には、この方法で解決しました:

_List<Item> newItems = databaseHandler.getItems();
ListArrayAdapter.clear();
ListArrayAdapter.addAll(newItems);
ListArrayAdapter.notifyDataSetChanged();
databaseHandler.close();
_

最初にアダプターからデータをクリアし、次にアイテムの新しいコレクションを追加してから、notifyDataSetChanged();を設定しました。これは最初は明確ではなかったので、これを指摘したかったのです。 notifyDataSetChanged()を呼び出さないと、ビューは更新されないことに注意してください。

59
LoneDuck

私の理解では、データが変更されたときにListViewをすぐに更新する場合は、notifyDataSetChanged()RunOnUiThread()を呼び出す必要があります。

private void updateData() {
    List<Data> newData = getYourNewData();
    mAdapter.setList(yourNewList);

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
                mAdapter.notifyDataSetChanged();
        }
    });
}
12
khcpietro

ListViewのコンテンツを更新するために新しいアダプターを作成する必要はありません。アダプタをフィールドに保存し、次のコードでリストを更新するだけです。

mAdapter.setList(yourNewList);
mAdapter.notifyDataSetChanged();

それを明確にするために、アクティビティは次のようになります。

private YourAdapter mAdapter;

protected void onCreate(...) {

    ...

    mAdapter = new YourAdapter(this);
    setListAdapter(mAdapter);

    updateData();
}

private void updateData() {
    List<Data> newData = getYourNewData();
    mAdapter.setList(yourNewList);
    mAdapter.notifyDataSetChanged();
}
11
Gubbel

同じアダプターに異なるデータを補充することは、より良いまたは最も良い方法だと思います。正しい引数(この場合、名前として表示するデータリスト)を使用して、このメソッドをアダプタクラスに入れます。更新されたリスト(私の場合は名前)でリストのデータを更新するときに、

public void refill(ArrayList<BeanDatabase> names) {
    list.clear();
    list.addAll(names);
    list.notifyDataSetChanged();
}

アダプターを変更したり、リストが更新されたときにアダプターを何度も設定したりすると、強制終了エラーはある時点で確実に問題を引き起こします。 (エラー:リストデータは更新されましたが、アダプターはリストビューに通知しません)

3
himb2001

私もinvalidate()、invalidateViews()、notifyDataSetChanged()を試しました。それらはすべて特定のコンテキストで機能する可能性がありますが、私の場合はうまくいきませんでした。

私の場合、リストに新しい行を追加する必要がありましたが、機能しません。新しいアダプターを作成することで問題が解決しました。

デバッグ中に、データはそこにあるがレンダリングされていないことに気付きました。 invalidate()またはinvalidateViews()がレンダリングされない場合(これが想定されている)、何が起こるかわかりません。

変更されたデータを更新するために新しいAdapterオブジェクトを作成することは悪い考えではないようです。それは間違いなく動作します。唯一のマイナス面は、アダプターに新しいメモリを割り当てるのにかかる時間ですが、Androidシステムが十分にスマートであり、効率を維持するためにそれを処理すると仮定すると問題ありません。

これを式から外すと、フローはnotifyDataSetChangedを呼び出すのとほぼ同じになります。ある意味で、どちらの場合でも同じアダプター関数のセットが呼び出されます。

だから、私たちは多くを失いませんが、多くを獲得しています。

3
Deepak G M

私はinvalidateViews()を使用して同じことをしていますが、それは私にとってはうまくいきます。すぐに無効にする場合は、invalidateViewsを呼び出した後にpostInvalidateを呼び出してみてください。

2
ingo

リストビューのコンテンツを更新する以下のコードで:

private ListView listViewBuddy;
private BuddyAdapter mBuddyAdapter;
private ArrayList<BuddyModel> buddyList = new ArrayList<BuddyModel>();

onCreate()

listViewBuddy = (ListView)findViewById(R.id.listViewBuddy);
mBuddyAdapter = new BuddyAdapter();
listViewBuddy.setAdapter(mBuddyAdapter);

onDataGet(Webサービス呼び出し後、またはローカルデータベースまたはその他から):

mBuddyAdapter.setData(buddyList);
mBuddyAdapter.notifyDataSetChanged();

BaseAdapter

private class BuddyAdapter extends BaseAdapter { 

    private ArrayList<BuddyModel> mArrayList = new ArrayList<BuddyModel>();
    private LayoutInflater mLayoutInflater= (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    private ViewHolder holder;

    public void setData(ArrayList<BuddyModel> list){
        mArrayList = list;
    }

    @Override
    public int getCount() {
        return mArrayList.size();
    }

    @Override
    public BuddyModel getItem(int position) {
        return mArrayList.get(position);
    }

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

    private class ViewHolder {
        private TextView txtBuddyName, txtBuddyBadge;

    }
    @SuppressLint("InflateParams")
    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = mLayoutInflater.inflate(R.layout.row_buddy, null);
            // bind views
            holder.txtBuddyName = (TextView) convertView.findViewById(R.id.txtBuddyName);
            holder.txtBuddyBadge = (TextView) convertView.findViewById(R.id.txtBuddyBadge);

            // set tag
            convertView.setTag(holder);
        } else {
            // get tag
            holder = (ViewHolder) convertView.getTag();
        }

        holder.txtBuddyName.setText(mArrayList.get(position).getFriendId());

        int badge = mArrayList.get(position).getCount();
        if(badge!=0){
            holder.txtBuddyBadge.setVisibility(View.VISIBLE);
            holder.txtBuddyBadge.setText(""+badge);
        }else{
            holder.txtBuddyBadge.setVisibility(View.GONE);
        }   

        return convertView;
    }
}

いつでもしたいリストビューの更新 2行以下のコードを呼び出すだけです:

 mBuddyAdapter.setData(Your_Updated_ArrayList);
 mBuddyAdapter.notifyDataSetChanged();

完了

1
Hiren Patel

これだけが毎回うまくいきますが、他の合併症やパフォーマンスの問題を引き起こすかどうかはわかりません。

private void updateListView(){
        listview.setAdapter(adapter);
    }
1
savante

別の簡単な方法:

//In your ListViewActivity:
public void refreshListView() {
    listAdapter = new ListAdapter(this);
    setListAdapter(listAdapter);
}
0
dnst