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

对于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的方法

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值