android progressbar listview,Android 如何在 ListView 中更新 ProgressBar 进度

=======================ListView原理==============================

44cc4c0c44d728f470176ed97a103379.png

Android 的 ListView 的原理打个简单的比喻就是:

演员演小品(假设演员都长一样,每个角色任何演员都可以演)

1b4cb98a649d857dee7123089c79c712.png

小品剧不需要为每个角色都招募一个演员。ListView 也没必要为每一个 Item 创建 View 对象。

小品剧的演员在一个角色表演完成后,会在后台换下一个角色的服装,等待需要表演的时候再出场。

ListView 会让未显示的 View 填充数据后缓存在后台,等待滑动时再将它显示出来。

小品演员换个服装就成了另一个角色,所以不能以角色来判断是哪个演员。

ListView 中的 Item 的样式是随填充的数据动态变化的,所以不能以某个样式作为Item的标识。

如果你是导演,你要警察这个角色在白领抬手时双手举起,你会怎们做?如果你找上次演过警察的那个演员,告诉他你在白领抬手时将双手举起。

那么有三个结果:一、他仍然演警察、他出色的完成了表演。二、他演厨师,结果白领抬手时厨师举起了手。三、他没上台,结果警察没举手。

ListView 中如果你根据某个 Item 的状态来获取它的 View 对象,通过线程改变它的状态,就会发生这三种情况。

那么要如何做呢?当然是告诉所有演员,谁扮演警察谁就在白领抬手时双手举起。那表演时如何判断谁演的是警察呢?警察帽子就是标志,谁戴着谁是警察。

ListView 中你要获取所有的 View 对象的集合,并为每一个 View 设置标识,传递需要更新状态的视图标识。更新前,在集合中找到标识匹配的 View 对象,让它做出相应的更新操作。

=====================ListView 中更新 ProgressBar=========================

知道这个 ListView 这个特性之后,就可以动手开始写了:

布局文件

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

activity_main

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

list_item

Java文件

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public class MainActivity extendsAppCompatActivity {private ListView listView; //列表控件

private List data; //数据源(模拟)

private MyAdapter adapter; //自定义适配器

@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);/*初始化控件*/listView=(ListView) findViewById(R.id.list_view);/*初始化数据*/data= new ArrayList<>();for (int i = 0; i < 30; i++) {//组装数据

MyObject myObject = newMyObject();

myObject.text= "按钮" +i;

myObject.progress= -1;//添加到数据源

data.add(myObject);

}/*填充适配器*/adapter= new MyAdapter(this, data);

listView.setAdapter(adapter);

}/*** 实体对象,用于保存数据*/

classMyObject {

Integer progress;//下载进度

String text; //按钮文字

}

}

MainActivity

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public class MyAdapter extendsBaseAdapter {private Context context; //上下文对象用于视图填充

private List data; //需要适配的数据源

private List viewList; //View对象集合

public MyAdapter(Context context, Listdata) {this.viewList = new ArrayList<>();this.context =context;this.data =data;

}

@Overridepublic intgetCount() {returndata.size();

}

@Overridepublic Object getItem(intposition) {returndata.get(position);

}

@Overridepublic long getItemId(intposition) {returnposition;

}

@Overridepublic View getView(final intposition, View convertView, ViewGroup parent) {finalViewHolder viewHolder;/*初始化控件*/

if (convertView == null) {

convertView= LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);

viewHolder= newViewHolder();

viewHolder.progressBar=(ProgressBar) convertView.findViewById(R.id.progress_bar);

viewHolder.button=(Button) convertView.findViewById(R.id.btn);

convertView.setTag(viewHolder);

}else{

viewHolder=(ViewHolder) convertView.getTag();

}/*添加控件样式*/

final MainActivity.MyObject myObject =data.get(position);

viewHolder.button.setText(myObject.text);

viewHolder.progressBar.setProgress(myObject.progress);/*设置按钮点击事件*/viewHolder.button.setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View v) {if (myObject.progress == -1) {

myObject.progress= 0;//如果未开始下载,启动异步下载任务

MyAsyncTask asyncTask = newMyAsyncTask(viewList, position);//添加THREAD_POOL_EXECUTOR可启动多个异步任务

asyncTask.executeOnExecutor(MyAsyncTask.THREAD_POOL_EXECUTOR, myObject);

}

}

});/*标识View对象*/

//将list_view的ID作为Tag的Key值

convertView.setTag(R.id.list_view, position);//此处将位置信息作为标识传递

viewList.add(convertView);returnconvertView;

}/*** 用于缓存控件ID*/

classViewHolder {

ProgressBar progressBar;

Button button;

}

}

MyAdapter

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public class MyAsyncTask extends AsyncTask{private MainActivity.MyObject myObject; //单个数据,用于完成后的处理

private List viewList; //视图对象集合,用于设置样式

private Integer viewId; //视图标识,用于匹配视图对象

public MyAsyncTask(ListviewList, Integer viewId) {this.viewList =viewList;this.viewId =viewId;

}

@OverrideprotectedVoid doInBackground(MainActivity.MyObject... params) {

myObject= params[0];/*模拟下载任务*/

for (int i = 0; i < 100; i++) {//发布进度

publishProgress(i);try{

Thread.sleep(100);

}catch(InterruptedException e) {

e.printStackTrace();

}

}return null;

}

@Overrideprotected voidonProgressUpdate(Integer... values) {

View view= null;/*匹配视图对象*/

for (int i = 0; i < viewList.size(); i++) {if (viewList.get(i).getTag(R.id.list_view) ==viewId) {//检查所有视图ID,如果ID匹配则取出该对象

view =viewList.get(i);break;

}

}if (view != null) {//将视图对象中缓存的ViewHolder对象取出,并使用该对象对控件进行更新

MyAdapter.ViewHolder viewHolder =(MyAdapter.ViewHolder) view.getTag();

viewHolder.progressBar.setProgress(values[0]);

}

myObject.progress= values[0];

}

@Overrideprotected voidonPostExecute(Void aVoid) {//更新数据源信息

myObject.progress = 100;

}

}

MyAsyncTask

实现效果

8caae5db85f751a134eab3008bf758f8.png

这里主要强调一下如何为View设置标识,以及从View集合中匹配标识:

首先是为View设置标识:

@Overridepublic View getView(final intposition, View convertView, ViewGroup parent) {finalViewHolder viewHolder;/*初始化控件*/

if (convertView == null) {

convertView= LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);

viewHolder= newViewHolder();

viewHolder.progressBar=(ProgressBar) convertView.findViewById(R.id.progress_bar);

viewHolder.button=(Button) convertView.findViewById(R.id.btn);

convertView.setTag(viewHolder);//记录ViewHolder对象,缓存控件实例

} else{

viewHolder=(ViewHolder) convertView.getTag();

}/*添加控件样式*/

//略去……

/*设置按钮点击事件*/

//略去……

/*标识View对象*/convertView.setTag(R.id.list_view, position);//此处将位置信息作为标识传递

viewList.add(convertView); //将每个View添加到视图集合中

/*** View.setTag(int Key,Object object)中的Key值必须唯一

* 传入任何常量都是无效的,必须传入R.id中生成的值

*

* 标识并非用于识别View对象,而是识别View的状态

* 就像警帽并非用于识别演员,而是识别演员当前扮演的角色

*

* View集合就像演员名单一样重要,如果没有它表演无从开展

*

* notifyDataSetChanged()虽然能更新列表,但是它是更新所有控件数据

* 相比于选择某个控件进行更新,这种方法性能开销大,体验差*/

returnconvertView;

}

然后是在更新时匹配标识:

@Overrideprotected voidonProgressUpdate(Integer... values) {

View view= null;/*匹配视图对象*/

for (int i = 0; i < viewList.size(); i++) { //上场名单清点

if (viewList.get(i).getTag(R.id.list_view) == viewId) { //服装确认匹配//检查所有视图ID,如果ID匹配则取出该对象

view =viewList.get(i);break;

}

}if (view != null) { //上场进行表演//将视图对象中缓存的ViewHolder对象取出,并使用该对象对控件进行更新

MyAdapter.ViewHolder viewHolder =(MyAdapter.ViewHolder) view.getTag();

viewHolder.progressBar.setProgress(values[0]);

}/*** 在更新时ViewList的重要性就体现出来了

* 遍历整个ViewList直到找到标识相同的视图

*

* 因为每次填充View时,View都会添加一个标识,而标识记录了当前的位置

* 所以标识代表某个视图在特定的位置,如果标识固定那么位置也就固定了

*

* 就像演员每次表演前,虽然角色谁都可以演,但是只要服装确定

* 那么只有穿着这服装且在上场名单内的演员才可以进行表演

**/}

其实更新 ListView 中的某个控件的状态真是是很麻烦的事,因为适配器会为视图填充新的数据,这就要求使用对象记录状态,比如在实体对象中添加完成与否的判断,还有完成进度的记录,并且在更新视图中也同步更新这些数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值