ListView高效刷新——刷新单条数据

来源:互联网 发布:js获取class为a的div 编辑:程序博客网 时间:2024/05/17 22:23

对于ListView数据的刷新大家都知道,改变Adapter的数据源,然后调用Adapter的notifyDateSetChanged()方法即可。

用的listview展示所有正在下载的内容。因为下载进度要实时更新,所以要不停的调用notifyDateSetChanged刷新数据。这样会不停的重新绘制整个listview的界面,性能开销非常大。而且如果每个item有图片的话,每个item的图片都需要重新加载,就算图片做了内存缓存,刷新一下图片也会闪一下,不停的刷新就会导致各个item的图片不停的闪,体验一点都不好。那么对于上面问题,有没有解决办法呢?当然是有的。我们可以针对某一个item进行局部更新,而不影响其它没有修改的item。那么具体如何实现的呢?

getView方法被多次调用(画面上能显示多少就会被调用多少次),并且在有获取网络图片的情况下会可能造成大量闪动或卡顿,极大的影响用户体验。

一些方法的介绍:

ListView.getFirstVisiblePosition():获取第一个可见的item
ListView.getLastVisiblePosition():获取最后一个可见的item

ListView.getItemAtPosition(position):获取item数据集
Adapter.getItem(position):获取item数据集,等同上面方法

ListView.getChildAt(position):获取到的是当前可见的第position项的itemview,获取的时候还需要做一个位置计算。

Adapter.getView(position, itemView , ListView ):刷新单个itemview界面

adapter.notifyDataSetChanged():是对listview的所有可见item(最上面和最下面半个也算)进行刷新,初始化listview或者手动调用此方法时都会调用getView且次数为item的可见个数。

listView.getAdapter():获取listview的adapter

实现原理:

(1)找到需要更新的item在adapter中的位置;
(2)更新adapter中item的数据data;
(3)如果该item在listView当前屏的可见范围内,则更新内容,否则不需要更新,待下次adapter刷新全部时再刷新;

更新方式:

方式1、获取itemview里的控件直接设置

View view = mListView.getChildAt(targetIndex - startShownIndex);TextView textView = (TextView) view.findViewById(R.id.textView);textView.setText(datas.get(targetIndex));

方式2、获取itemview然后调用getview方法

View view = mListView.getChildAt(targetIndex - startShownIndex);                      myAdapter.getView(targetIndex, view, mListView);//核心方法

方式3、直接更新listview的所有item

myAdapter.notifyDataSetChanged();//核心方法

demo如下:

package com.example.draggridview;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.AdapterView;import android.widget.Button;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/6/19. */public class MyActivity extends AppCompatActivity {    private ListView mListView;    private List<String> datas;    private MyAdapter myAdapter;    private Button btn,btn1, btn2;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_my);        datas = new ArrayList<>();        for (int i = 0; i < 20; i++) {            datas.add(i + "");        }        mListView = (ListView) findViewById(R.id.listview);        btn1 = (Button) findViewById(R.id.btn1);        btn2 = (Button) findViewById(R.id.btn2);        btn = (Button) findViewById(R.id.btn);        myAdapter = new MyAdapter(MyActivity.this, datas);        mListView.setAdapter(myAdapter);        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //1、找到item内容为5的position                String targetString = "5";                int targetIndex = -1;                for (int j = 0; j < mListView.getCount(); j++) {                    //通过listView获取item的数据集,等同于baseAdapter的getItem方法                    String itemString = mListView.getItemAtPosition(j).toString();                    if (targetString.equals(itemString)) {                        targetIndex = j;                        break;                    }                }                if (targetIndex >= 0) {                    //2、改变它的数据集                    datas.set(targetIndex, "改变!!!!");                    //3、可见时调用setText刷新界面                    int startShownIndex = mListView.getFirstVisiblePosition();                    int endShownIndex = mListView.getLastVisiblePosition();                    if (targetIndex >= startShownIndex && targetIndex <= endShownIndex) {                        View view = mListView.getChildAt(targetIndex - startShownIndex);                        TextView textView = (TextView) view.findViewById(R.id.textView);                        textView.setText(datas.get(targetIndex));                    }                }            }        });        btn1.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //1、找到item内容为8的position                String targetString = "8";                int targetIndex = -1;                for (int j = 0; j < mListView.getCount(); j++) {                    //通过listView获取item的数据集,等同于baseAdapter的getItem方法                    String itemString = mListView.getItemAtPosition(j).toString();                    if (targetString.equals(itemString)) {                        targetIndex = j;                        break;                    }                }                if (targetIndex >= 0) {                    //2、改变它的数据集                    datas.set(targetIndex, "改变!!!!");                    //3、可见时调用getView刷新界面                    int startShownIndex = mListView.getFirstVisiblePosition();                    int endShownIndex = mListView.getLastVisiblePosition();                    if (targetIndex >= startShownIndex && targetIndex <= endShownIndex) {                        View view = mListView.getChildAt(targetIndex - startShownIndex);//                        mListView.getAdapter().getView(targetIndex, view, mListView);                        myAdapter.getView(targetIndex, view, mListView);//核心方法                    }                }            }        });        btn2.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                //1、找到item内容为2的position                String targetString = "2";                int targetIndex = -1;                for (int j = 0; j < mListView.getCount(); j++) {                    //通过listView获取item的数据集,等同于baseAdapter的getItem方法                    String itemString = mListView.getItemAtPosition(j).toString();                    if (targetString.equals(itemString)) {                        targetIndex = j;                        break;                    }                }                if (targetIndex >= 0) {                    //2、改变它的数据集                    datas.set(targetIndex, "改变!!!!");                    //3、可见时调用getView刷新界面                    int startShownIndex = mListView.getFirstVisiblePosition();                    int endShownIndex = mListView.getLastVisiblePosition();                    if (targetIndex >= startShownIndex && targetIndex <= endShownIndex) {                        myAdapter.notifyDataSetChanged();//核心方法                    }                }            }        });        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            //参数:listview,listview的item布局,位置,ID            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                //数据集的变化                datas.set(position, "这是被更新的数据哦");                //滚动看不见之后再次可见时会显示这条数据                if (position != datas.size() - 1) {                    datas.set(position + 1, "这是被更新的数据哦,但是不展示");                }                //方法一                //通过listview的item拿到TextView来更新控件数据                //TextView testView = (TextView) view.findViewById(R.id.textView);                //testView.setText(datas.get(position));                //方法二                //通过调用getview来更新整个item                myAdapter.getView(position, view, mListView);                //方法三                //通过调用notifyDataSetChanged来更新整个listView                //myAdapter.notifyDataSetChanged();                //ID和position一样的值                Log.e("MainActivity", "position==" + position);                Log.e("MainActivity", "id==" + id);                //ListView.getItemAtPosition(position)等价于Adapter.getItem(position)                Log.e("MainActivity", "getItemAtPosition==" + mListView.getItemAtPosition(position).toString());            }        });    }}

activity_my.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout 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"    android:orientation="vertical"    tools:context=".MyActivity">    <Button        android:id="@+id/btn"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="setText改变字符串为5的item!!!"        android:textSize="25sp" />    <Button        android:id="@+id/btn1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="getView改变字符串为8的item!!!"        android:textSize="25sp" />    <Button        android:id="@+id/btn2"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="notifyDataSetChanged改变字符串为2的item!!!"        android:textSize="25sp" />    <ListView        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1" /></LinearLayout>

MyAdapter.java

package com.example.draggridview;import android.content.Context;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import java.util.List;/** * Created by Administrator on 2017/6/19. */public class MyAdapter extends BaseAdapter {    private Context mContext;    private List<String> datas;    public MyAdapter(Context context, List<String> datas) {        this.mContext = context;        this.datas = datas;    }    @Override    public int getCount() {        return datas == null ? 0 : datas.size();    }    @Override    public Object getItem(int position) {        return datas.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ViewHolder viewHolder = null;        if (convertView == null) {            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_adapter, null);            viewHolder = new ViewHolder();            viewHolder.mTextView = (TextView) convertView.findViewById(R.id.textView);            convertView.setTag(viewHolder);        } else {            viewHolder = (ViewHolder) convertView.getTag();        }        viewHolder.mTextView.setText(datas.get(position));        Log.e("MainActivity", "getView  position==" + position);        return convertView;    }    class ViewHolder {        private TextView mTextView;    }}

item_adapter.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <TextView        android:id="@+id/textView"        android:layout_width="match_parent"        android:layout_height="60dp"        android:gravity="center"        android:textSize="45sp"        android:text="1" /></LinearLayout>

测试结果:

1、直接设置setText:不会调用getView方法
2、获取itemview然后调用adapter.getview方法:只调用一次当前position的getview方法。
3、notifyDataSetChanged:会调用所有可见item的getview方法

参考:

ListView高效刷新——刷新单条数据

Android RecyclerView与ListView局部刷新

ListView实现Item局部刷新

面试 – ListView对其指定的子Item进行单独的刷新

listview局部刷新

ListView中单独更新某个Item的方法

原创粉丝点击