你还在用notifyDataSetChanged?
想到发这篇帖子是源于我的上一篇帖子#Testin杯#多线程断点续传后台下载 。
帖子中讲述的项目使用了listView这个控件,而且自定义了adapter。在更新item的进度条时发现每次使用notifyDataSetChanged(),都会去调用自定义adapter中的getView方法。这时问题就出现了,用notifyDataSetChanged方法去更新listView中的item,是更新需要更新的Item呢?还是更新所有的item呢?如果是更新所有的item那么效率不就会很低吗?有什么办法可以解决这个问题呢?
怀着心中的疑惑,我开始了这次的实验。。。
我的想法很简单现实模拟远程下载文件,创建一个Activity做主界面,主界面采用listView。然后自定义一个adapter实现BaseAdapter,再创建一个线程类,线程类当中采用循环的方式不断的往adapter发送消息.然后使用notifyDataSetChanged方法更新界面,在调用getView方法时在控制台输出语句,这样我就可以知道notifyDatatSetChanged方法执行时是更新一个item还是更新所有的item了。
有了思路就好办了,我们先建立一个类,叫FileState。
- package edu.notify.viking.entity;
- public class FileState
- {
- String fileName;//文件名字
- int completeSize;//完成的长度
- boolean state;//文件状态,true为已经完成,false为未完成
- public String getFileName() {
- return fileName;
- }
- public void setFileName(String fileName) {
- this.fileName = fileName;
- }
- public int getCompleteSize() {
- return completeSize;
- }
- public void setCompleteSize(int completeSize) {
- this.completeSize = completeSize;
- }
- public boolean isState() {
- return state;
- }
- public void setState(boolean state) {
- this.state = state;
- }
- }
复制代码
这个类中有3个属性,分别是文件名字,文件已经下载的长度,还有文件当前的状态。然后就是get与set方法。这个类的作用我想大家应该一眼就明白了,没错,既然使用了listView,我在主界面就想着要定义一个List,这个list当中的内容当然就是我们FileState啦。
接着我们去实现主界面。创建主界面MainActivity
- package edu.notify.viking.activity;
- import java.util.ArrayList;
- import java.util.List;
- import edu.notify.viking.adapter.MyAdapter;
- import edu.notify.viking.entity.FileState;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.ListView;
- public class MainActivity extends Activity
- {
- private List<FileState> list=new ArrayList<FileState>();
- private ListView listView;
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- initFileState();//先对FileState进行初始化
- initUI();//对界面进行初始化
- }
- /**
- * 把数据放进list中,因为是测试所以我手工添加数据
- * **/
- private void initFileState()
- {
- //给FileState赋值
- for(int i =1;i<8;i++)
- {
- FileState fileState=new FileState();
- fileState.setFileName(i+".mp3");//名字
- fileState.setCompleteSize(100);//初始化下载程度
- fileState.setState(true);
- list.add(fileState);
- }
- FileState f=new FileState();
- f.setFileName("8.mp3");
- f.setCompleteSize(0);
- f.setState(false);
- list.add(f);
- }
- private void initUI()
- {
- listView = (ListView)this.findViewById(R.id.listview);
- MyAdapter adapter = new MyAdapter(list,this);
- listView.setAdapter(adapter);
- adapter.setListView(listView);
- }
- }
复制代码
接着我创建了自定义的adapter,并将他与listView绑定在一起。然后将listView传进了adapter中。
那我们来看看adapter中是如何实现的吧。新建一个adapter,取名叫MyAdatper继承BaseAdapter.
- <font face="宋体">package edu.notify.viking.adapter;
- import java.util.List;
- import edu.notify.viking.activity.R;
- import edu.notify.viking.down.Downloader;
- import edu.notify.viking.entity.FileState;
- import android.content.Context;
- import android.os.Handler;
- import android.os.Message;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.ListView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class MyAdapter extends BaseAdapter
- {
- private List<FileState> list;
- private Context context;
- private LayoutInflater inflater=null;
- private ListView listView;
- private Handler mHandler = new Handler()
- {
- @Override
- public void handleMessage(Message msg)
- {
- if(msg.what==1)
- {
- String name=(String)msg.obj;
- int length=msg.arg1;
- for(int i=0;i<list.size();i++)
- {
- FileState fileState=list.get(i);
- if(fileState.getFileName().equals(name))
- {
- fileState.setCompleteSize(length);
- list.set(i, fileState);
- break;
- }
- }
- notifyDataSetChanged();
- }
- }
- };
- public MyAdapter(List<FileState> list,Context context)
- {
- inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- this.list=list;
- }
- class ViewHolder
- {
- public TextView fileName;//文件名称
- public ProgressBar progressBar;//进度条
- public TextView percent;//百分比
- public ImageView down;//下载
- }
- public int getCount()
- {
- // TODO Auto-generated method stub
- return list.size();
- }
- public Object getItem(int position)
- {
- // TODO Auto-generated method stub
- return list.get(position);
- }
- public long getItemId(int position)
- {
- // TODO Auto-generated method stub
- return position;
- }
- public View getView(int position, View convertView, ViewGroup parent)
- {
- ViewHolder holder;
- if(convertView==null)
- {
- convertView=inflater.inflate(R.layout.main_item, null);
- holder=new ViewHolder();
- holder.fileName=(TextView)convertView.findViewById(R.id.fileName);
- holder.progressBar=(ProgressBar)convertView.findViewById(R.id.down_progressBar);
- holder.percent = (TextView) convertView.findViewById(R.id.percent_text);
- holder.down = (ImageView) convertView.findViewById(R.id.down_view);
- convertView.setTag(holder);
- }
- else
- {
- holder=(ViewHolder)convertView.getTag();
- }
- FileState fileState=list.get(position);
- final String name = fileState.getFileName();
- System.out.println(name+"---run getView");
- //如果文件状态为已经下载
- if(fileState.isState()==true)
- {
- holder.fileName.setText(fileState.getFileName());
- //下载完成的文件,进度条被隐藏
- holder.progressBar.setVisibility(ProgressBar.INVISIBLE);
- //设置为已下载
- holder.percent.setText("已下载");
- //下载完成的文件,下载按钮被隐藏,防止重复下载
- holder.down.setVisibility(ImageView.INVISIBLE);
- }
- else
- {
- holder.fileName.setText(fileState.getFileName());
- holder.progressBar.setVisibility(ProgressBar.VISIBLE);
- holder.progressBar.setProgress(fileState.getCompleteSize());
- holder.percent.setText(fileState.getCompleteSize()+"%");
- holder.down.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- Downloader down= new Downloader(name,mHandler);
- down.download();
- }
- });
- if(fileState.getCompleteSize()==100)
- {
- holder.progressBar.setVisibility(ProgressBar.INVISIBLE);
- holder.percent.setText("已下载");
- holder.down.setVisibility(ProgressBar.INVISIBLE);
- fileState.setState(true);
- list.set(position, fileState);
- }
- }
- return convertView;
- }
- public void setListView(ListView listView) {
- this.listView = listView;
- }
- }
- </font>
复制代码
为了运行的效率,我在adapter中定义了一个内部类,ViewHolder,其中的属性都是我们要绘制出来的控件。主要的绘制工作在于getView这个方法,在getView中我们对变量初始化以后,就将list当中对应的FileState拿了出来,根据文件的状态进行了分别的处理,下载完成的怎么怎么显示。。。下载为完成的怎么怎么显示。。。这些都不难,很容易就看明白了。在这里面我们实现了下载按钮这个点击事件,这个事件中的代码也很简单,就是创建一个Downloader对象,然后调用其中的download方法进行下载。在这个类中我们看到,其中创建了一个Handler对象,并在里面实现它的消息处理方法handleMessage。当我们点击下载图标时会把这个Handler对象传进Downloader这个类中。当文件开始下载时,下载完成的数据长度将会传到handlerMessage这个方法中被处理,我们在这个方法中对FileState与list做了更新,然后调用了notifyDatatSetChanged方法.
接下来我们来看最后一个类。创建Downloader类。
- package edu.notify.viking.down;
- import java.util.Map;
- import android.os.Handler;
- import android.os.Message;
- public class Downloader
- {
- private String fileName;
- private Handler mHandler;
- public Downloader(String fileName, Handler handler)
- {
- super();
- this.fileName = fileName;
- mHandler = handler;
- }
- public void download()
- {
- new MyThread().start();
- }
- class MyThread extends Thread
- {
- @Override
- public void run()
- {
- for(int i=0;i<=100;i++)
- {
- System.out.println("i:"+i);
- try {
- this.currentThread().sleep(1000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- Message msg=Message.obtain();
- msg.what=1;
- msg.obj=fileName;
- msg.arg1=i;
- mHandler.sendMessage(msg);
- }
- }
- }
- }
复制代码
先是main.xml
- <font face="宋体"><?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <ListView
- android:id="@+id/listview"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:fastScrollEnabled="true"
- />
- </LinearLayout>
- </font>
复制代码
- <font face="宋体"><?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:id="@+id/fileName"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- />
- <ProgressBar
- android:id="@+id/down_progressBar"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@android:style/Widget.ProgressBar.Horizontal"
- />
- <TextView
- android:id="@+id/percent_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- <ImageView
- android:id="@+id/down_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/down"
- />
- </LinearLayout></font>
复制代码
<ignore_js_op>
从图中我们可以看见,尽管我们只是想更新8.mp3这个item的进度条,但是所有的进度条都被更新了,每次使用notifyDataSetChanged方法,对会调用8次getView方法。天哪。这个效率。。。
这不是我们想要的,我们想要的是什么?我们想要的就是如果只需要更新8.mp3这个item,那么其他的item将保持不变,不需要更新他们。那么我们该怎么解决这个问题呢?
其实这个问题的解决也不麻烦,所谓难者不会,会者不难啊。我们只需要修改adapter这个类,在其中添加一个方法即可。现在我们来看更新后的adapter类。
- <font face="宋体">package edu.notify.viking.adapter;
- import java.util.List;
- import edu.notify.viking.activity.R;
- import edu.notify.viking.down.Downloader;
- import edu.notify.viking.entity.FileState;
- import android.content.Context;
- import android.os.Handler;
- import android.os.Message;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
- import android.widget.ListView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class MyAdapter extends BaseAdapter
- {
- private List<FileState> list;
- private Context context;
- private LayoutInflater inflater=null;
- private ListView listView;
- private Handler mHandler = new Handler()
- {
- @Override
- public void handleMessage(Message msg)
- {
- if(msg.what==1)
- {
- String name=(String)msg.obj;
- int length=msg.arg1;
- for(int i=0;i<list.size();i++)
- {
- FileState fileState=list.get(i);
- if(fileState.getFileName().equals(name))
- {
- fileState.setCompleteSize(length);
- list.set(i, fileState);
- updateView(i);//用我们自己写的方法
- break;
- }
- }
- //notifyDataSetChanged();不用了
- }
- }
- };
- public MyAdapter(List<FileState> list,Context context)
- {
- inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- this.list=list;
- }
- class ViewHolder
- {
- public TextView fileName;//文件名称
- public ProgressBar progressBar;//进度条
- public TextView percent;//百分比
- public ImageView down;//下载
- }
- /**
- * 用于更新我们想要更新的item
- * @param itemIndex 想更新item的下标
- * **/
- private void updateView(int itemIndex)
- {
- //得到第1个可显示控件的位置,记住是第1个可显示控件噢。而不是第1个控件
- int visiblePosition = listView.getFirstVisiblePosition();
- //得到你需要更新item的View
- View view = listView.getChildAt(itemIndex - visiblePosition);
- FileState fileState=list.get(itemIndex);
- final String name=fileState.getFileName();
- System.out.println(name+"---run updateView");
- if(fileState.isState()==false)
- {
- ViewHolder holderOne=new ViewHolder();
- //start:初始化
- holderOne.fileName=(TextView)view.findViewById(R.id.fileName);
- holderOne.progressBar=(ProgressBar)view.findViewById(R.id.down_progressBar);
- holderOne.percent = (TextView) view.findViewById(R.id.percent_text);
- holderOne.down = (ImageView) view.findViewById(R.id.down_view);
- //end
- holderOne.fileName.setText(fileState.getFileName());
- holderOne.progressBar.setVisibility(ProgressBar.VISIBLE);
- holderOne.progressBar.setProgress(fileState.getCompleteSize());
- holderOne.percent.setText(fileState.getCompleteSize()+"%");
- holderOne.down.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- Downloader down= new Downloader(name,mHandler);
- down.download();
- }
- });
- if(fileState.getCompleteSize()==100)
- {
- holderOne.progressBar.setVisibility(ProgressBar.INVISIBLE);
- holderOne.percent.setText("已下载");
- holderOne.down.setVisibility(ProgressBar.INVISIBLE);
- fileState.setState(true);
- list.set(itemIndex, fileState);
- }
- }
- }
- public int getCount()
- {
- // TODO Auto-generated method stub
- return list.size();
- }
- public Object getItem(int position)
- {
- // TODO Auto-generated method stub
- return list.get(position);
- }
- public long getItemId(int position)
- {
- // TODO Auto-generated method stub
- return position;
- }
- public View getView(int position, View convertView, ViewGroup parent)
- {
- ViewHolder holder;
- if(convertView==null)
- {
- convertView=inflater.inflate(R.layout.main_item, null);
- holder=new ViewHolder();
- holder.fileName=(TextView)convertView.findViewById(R.id.fileName);
- holder.progressBar=(ProgressBar)convertView.findViewById(R.id.down_progressBar);
- holder.percent = (TextView) convertView.findViewById(R.id.percent_text);
- holder.down = (ImageView) convertView.findViewById(R.id.down_view);
- convertView.setTag(holder);
- }
- else
- {
- holder=(ViewHolder)convertView.getTag();
- }
- FileState fileState=list.get(position);
- final String name = fileState.getFileName();
- System.out.println(name+"---run getView");
- //如果文件状态为已经下载
- if(fileState.isState()==true)
- {
- holder.fileName.setText(fileState.getFileName());
- //下载完成的文件,进度条被隐藏
- holder.progressBar.setVisibility(ProgressBar.INVISIBLE);
- //设置为已下载
- holder.percent.setText("已下载");
- //下载完成的文件,下载按钮被隐藏,防止重复下载
- holder.down.setVisibility(ImageView.INVISIBLE);
- }
- else
- {
- holder.fileName.setText(fileState.getFileName());
- holder.progressBar.setVisibility(ProgressBar.VISIBLE);
- holder.progressBar.setProgress(fileState.getCompleteSize());
- holder.percent.setText(fileState.getCompleteSize()+"%");
- holder.down.setOnClickListener(new View.OnClickListener()
- {
- public void onClick(View v)
- {
- Downloader down= new Downloader(name,mHandler);
- down.download();
- }
- });
- if(fileState.getCompleteSize()==100)
- {
- holder.progressBar.setVisibility(ProgressBar.INVISIBLE);
- holder.percent.setText("已下载");
- holder.down.setVisibility(ProgressBar.INVISIBLE);
- fileState.setState(true);
- list.set(position, fileState);
- }
- }
- return convertView;
- }
- public void setListView(ListView listView) {
- this.listView = listView;
- }
- }
- </font>
复制代码
<ignore_js_op>
看到红色箭头的地方就是修改过的。然后多添加了一个updateView方法。这个方法需要传入你想更新的item下标。
最核心的地方是这2句代码。
<ignore_js_op>
主要的意思就是根据你想要更新的item下标去得到这个item的View对象,这样你就可以为所欲为啦。哈哈哈哈哈。。。{:soso_e144:}
咱们来看看运行效果。
<ignore_js_op>
这里我改为同时更新2个item,看看这样会不会出错,可以看到,运行的很正常。控制台的打印结果也只是更新了7-8.mp3这2个item。
好了,文章到此已经结束了,肯定有人要骂我了,这么简单的东西,你啰嗦了半天。整的我都没怎么听懂。{:soso__2830444864204702144_2:} 不管怎样,都要感谢CCTV,MTV,还有KTV。当然还有我们安卓巴士提供的这个平台。希望安卓巴士越办越好
你还在用notifyDataSetChanged?的更多相关文章
- Android开发资源推荐第2季
Android CPU监控想法,思路,核心技术和代码 Android App /Task/Stack 总体分析 http://www.eoeandroid.com/thread-161703-1-1. ...
- 收藏的技术文章链接(ubuntu,python,android等)
我的收藏 他山之石,可以攻玉 转载请注明出处:https://ahangchen.gitbooks.io/windy-afternoon/content/ 开发过程中收藏在Chrome书签栏里的技术文 ...
- 为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment?
在一个 Android 应用中,我使用 FragmentPagerAdapter 来 处理多 Fragment 页面的横向滑动.不过我碰到了一个问题,即当 Fragment 对应的数据集发生改变时,我 ...
- 从源代码的角度分析--在BaseAdapter调用notifyDataSetChanged()之后发生了什么
导师安排我做一个小项目,其中涉及到利用Adapter作为ListView的适配器,为ListView提供数据.选中某一项后,要让这一项变成选中状态,也就是背景图片要换一下.下面我就用一个小例子来模拟. ...
- 【转】为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment?
为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment? 转自:http://www.apkbus.com/android- ...
- Android 关于ListView中adapter调用notifyDataSetChanged无效的原因
话说这个问题已经困扰我很久了,一直找不到原因,我以为只要数据变了,调用adapter的notifyDataSetChanged就会更新列表,最近在做微博帐号管理这一块,想着动态更新列表,数据是变了,但 ...
- ##解决 ViewPager 调用 notifyDataSetChanged()无刷新:原理、解决办法##
一.原理 转自:http://www.cnblogs.com/maoyu417/p/3740209.html 转载 http://www.67tgb.com/?p=624 最近项目结束,搞了一次代码分 ...
- PopupWindow的使用以及ArrayAdatper.notifyDataSetChanged()无效详解
Android的对话框有两种:PopupWindow和AlertDialog.它们的不同点在于: AlertDialog的位置固定,而PopupWindow的位置可以随意 AlertDialog是非阻 ...
- 为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment?【转载】
转载自:http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifyDataSetChanged-does-not-work.html ...
随机推荐
- 【模板】DFS
int dx[] = { 0,1,0,-1 }; int dy[] = { 1,0,-1,0 }; void dfs()//参数用来表示状态 { if (到达终点状态) { ...//根据题意来添加 ...
- tendermint学习
怎么把两个节点变成验证节点 1. 两个节点分别启动 2. 两个节点同时把自己的公钥信息添加到对方的创始快配置文件中,总而言之,创始块一样 3. unsafe_reset_priv_validator ...
- pandas协助工具
pandas有时候操作很不方便,也有可能是我不熟练吧,反正就是各种别扭.下面是我写的一个简单的json数据操作工具,能够完成简单的数据分析工作,后续会不断完善的 # coding=utf-8 impo ...
- Java中String类
String类 一.String类的用途 对字符串的存储与操作,即包含多个字符的字符数据,这个String类提供了数值不可改变的字符串. String类为什么不可改变的字符串,因为String类是fa ...
- return阻止js继续向下执行
终止JS运行有如下几种可能: 终止函数的运行的方式有两种 在函数中使用return,则当遇到return时,函数终止执行,控制权继续向下运行 在函数中使用try-catch异常处理,需要结束时,使用t ...
- LintCode-56.两数之和
两数之和 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 1 到 n, ...
- week1 技术随笔
类别c 内容c 开始时间s 结束时间e 被打断时间I 总计(min) 9.5 随笔 构建之法福后感 22:00 24:00 7 113 9.6 分析 需求分析 9:00 9:30 2 28 编码 词频 ...
- php缓存技术——memcache常用函数详解
php缓存技术——memcache常用函数详解 2016-04-07 aileen PHP编程 Memcache函数库是在PECL(PHP Extension Community Library)中, ...
- Linux服务器记录并查询历史操作记录
Linux服务器在使用过程中,经常会有除自己之外的其他人员使用.并不是每个人都对Linux服务器特别熟悉,难免会有一些操作导致服务器报错. 因此,监控Linux服务器的操作并记录下来,是非常有必要的! ...
- 关于如何解决PHPCMS V9内容搜索显示不全问题解决方案
站长朋友们都晓得只要是开源的PHP程序都会有漏洞存在.如果想完美的建站就需要自己去研究打补丁了.最近很多站长联系小编咨询用phpcms建站当在首页搜索内容的时候有的居然搜索不到.小编感到很是奇怪于是就 ...