网上找资料看到一段代码,还是很不错的,至少里面逻辑处理挺好的,
但是如果我要实现局部更新单个ItemView的话不想用notifyDataSetChanged()可以用本文最末尾的方法测试下。
MainActivity.java Activity类
package com.example.androidlistprogress;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Random;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener{
int jobcounter = 0 ;
private static final int ADDJOB = 1001;
private static final int PROCESSADD = 1002;
private static final int PROCESSDONE = 1003;
private static final int ITEMBUTTON_CLICKED = 1004;
private static final String TAG = "ListviewTest";
protected static final long REFRESH_INTERVAL = 100;
protected boolean mBusy = false ;
long lastupdatetime = 0 ;
Object lock = new Object() ;
ListView listview ;
Button buttonadd ;
AddjavaListAdapter adapter ;
LayoutInflater inflater ;
LinkedHashMap<Integer, ListInfo> listdatas ;
LinkedHashMap<Integer, ListInfo> addlist = new LinkedHashMap<Integer, MainActivity.ListInfo>() ;
List<Integer> delidlist = new ArrayList<Integer>() ;
Handler mainhandler = new Handler(){
public void handleMessage(android.os.Message msg) {
long v = System.currentTimeMillis() - lastupdatetime ;
switch (msg.what) {
case ADDJOB:
//if (inView(msg.arg1) && !mBusy) {
// Log.i(TAG, " ADDJOB done!") ;
updateListView();
lastupdatetime += REFRESH_INTERVAL ;
//}
break;
case PROCESSADD:
if ( !mBusy && v>REFRESH_INTERVAL) {
updateListView();
lastupdatetime = System.currentTimeMillis() ;
}
break;
case ITEMBUTTON_CLICKED:{
if(!listdatas.get(msg.arg1).running ) {
synchronized (listdatas.get(msg.arg1).lock) {
listdatas.get(msg.arg1).lock.notifyAll() ;
}
}
listdatas.get(msg.arg1).running = !listdatas.get(msg.arg1).running ;
if ( !mBusy ) {
updateListView();
lastupdatetime += REFRESH_INTERVAL ;
}
break;
}
case PROCESSDONE:
// Log.i(TAG, " PROCESSDONE done!"+msg.arg1) ;
synchronized (lock) {
delidlist.add(msg.arg1) ;
}
updateListView();
lastupdatetime += REFRESH_INTERVAL ;
break;
default:
break;
}
};
};
void updateListView(){
synchronized (lock) {
for (Integer delid : delidlist) {
Log.i(TAG, " PROCESSDONE done!"+delid) ;
listdatas.remove(delid) ;
}
listdatas.putAll(addlist) ;
for (ListInfo info : addlist.values()) {
//启动工作线程
new WorkThread("workthread#"+jobcounter,info).start() ;
jobcounter++ ;
}
//清空 delidlist 和 addlist
delidlist.clear() ;
addlist.clear() ;
}
adapter.notifyDataSetChanged();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
listdatas = new LinkedHashMap<Integer, ListInfo>() ;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview = (ListView) findViewById(R.id.listView001) ;
adapter = new AddjavaListAdapter();
listview.setAdapter(adapter) ;
//设置 当listview 进行上下拖动操作时的状态
listview.setOnScrollListener( new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
mBusy = false;
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
mBusy = true;
break;
case OnScrollListener.SCROLL_STATE_FLING:
mBusy = true;
break;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
}) ;
buttonadd = (Button) findViewById(R.id.button_listaddjob);
buttonadd.setOnClickListener(this);
inflater = LayoutInflater.from(this);
}
// 存放单条 listview 的数据
class ListInfo{
@Override
public String toString() {
return "ListInfo [index=" + index + ", id=" + id + ", running="
+ running + ", title=" + title + ", process=" + process
+ "]";
}
int index ;
long id ;
boolean running = true ;
String title ;
int process ;
Object lock = new Object();
}
class ViewHodler{
TextView text ;
ProgressBar bar ;
Button button ;
ItemClickListener listener;
}
// listview的适配器
class AddjavaListAdapter extends BaseAdapter {
@Override
public int getCount() {
return listdatas.keySet().size();
}
@Override
public Object getItem(int position) {
//从 listdata里获取 对应的数据 ,因为有删除的缘故.在有任务完成后 position不等于listdata的key
Object[] d = listdatas.keySet().toArray() ;
int c = (Integer)d[position] ;
// Log.i(TAG, "~~~~~getItem~~position["+position+"] [c="+c+"]") ;
return listdatas.get(c) ;
}
@Override
public long getItemId(int position) {
return ((ListInfo)this.getItem(position)).id ;
}
@Override
public View getView(int position, View v, ViewGroup parent) {
ViewHodler holder ;
// 获取单条item 的view对象
if (v==null) {
v = inflater.inflate(R.layout.listview_item, null) ;
holder = new ViewHodler() ;
holder.text = (TextView) v.findViewById(R.id.textView_item) ;
holder.bar = (ProgressBar) v.findViewById(R.id.progressBar_item);
holder.button = (Button) v.findViewById(R.id.button_item) ;
holder.listener = new ItemClickListener() ;
v.setTag(holder) ;
}else{
holder = (ViewHodler) v.getTag();
}
//将数据显示到每个对应的 view上.
final ListInfo data = (ListInfo)getItem(position) ;
holder.listener.setId(data.index) ;
holder.button.setOnClickListener(holder.listener) ;
holder.text.setText(data.title) ;
holder.bar.setProgress(data.process) ;
if (data.running) {
holder.button.setText("正在运行 ") ;
}else{
holder.button.setText("开始") ;
}
return v;
}
}
class ItemClickListener implements OnClickListener{
private int id ;
public void setId(int id) {
this.id = id;
}
@Override
public void onClick(View v) {
Log.i(TAG,"button clicked! "+id +"|"+listdatas.get(id).running+"-->"+!listdatas.get(id).running);
sendMessageToHandler(ITEMBUTTON_CLICKED,id) ;
}
}
class WorkThread extends Thread{
ListInfo in ;
public WorkThread(String name ,ListInfo in){
super(name) ;
this.in = in ;
}
@Override
public void run() {
ListInfo sdata = listdatas.get(in.index) ;
while(sdata.process<100) {
//如果暂停 则等待
if(!listdatas.get(in.index).running ) {
synchronized (listdatas.get(in.index).lock) {
try {
listdatas.get(in.index).lock.wait() ;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//模拟耗时任务操作
try {
Thread.sleep((int)(3000*new Random().nextDouble()));
} catch (InterruptedException e) {
e.printStackTrace();
}
sdata.process += new Random().nextInt(15)+1 ;
sendMessageToHandler(PROCESSADD,in.index) ;
}
//发送任务结束消息
if (sdata.process>=100) {
sendMessageToHandler(PROCESSDONE,in.index) ;
// Log.i(TAG, this.getName()+"#done") ;
}
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_listaddjob:{
ListInfo info = new ListInfo() ;
info.title = "file" + jobcounter ;
info.process = 0 ;
info.id = jobcounter ;
info.index = jobcounter ;
synchronized (lock) {
addlist.put(jobcounter, info) ;
}
sendMessageToHandler(ADDJOB,jobcounter) ;
break;
}
default:
break;
}
}
void sendMessageToHandler(int what,int arg1){
Message message = mainhandler.obtainMessage() ;
message.what = what ;
message.arg1 = arg1 ;
message.sendToTarget() ;
}
}
布局文件 listview_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listview_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/textView_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="TextView" />
<ProgressBar
android:id="@+id/progressBar_item"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="0.75" />
<Button
android:id="@+id/button_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:focusable="false"
android:text="start progress" />
</LinearLayout>
布局文件 activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/button_listaddjob"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="add a progress" />
<ListView
android:id="@+id/listView001"
android:layout_below="@id/button_listaddjob"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</RelativeLayout>
程序运行效果
- public void updateView(int itemIndex) {
- //得到第一个可显示控件的位置,
- int visiblePosition = mListView.getFirstVisiblePosition();
- //只有当要更新的view在可见的位置时才更新,不可见时,跳过不更新
- if (itemIndex - visiblePosition >= 0) {
- //得到要更新的item的view
- View view = mListView.getChildAt(itemIndex - visiblePosition);
- //从view中取得holder
- ViewHolder holder = (ViewHolder) view.getTag();
- HashMap<String, Object> item = data.get(itemIndex);
- holder.listItem = (RelativeLayout) view.findViewById(R.id.rl_item);
- holder.ibPlay = (ImageButton) view.findViewById(R.id.ib_play);
- holder.ibDelete = (ImageButton) view.findViewById(R.id.ib_delete);
- holder.tvName = (TextView) view.findViewById(R.id.tv_record_sound_name);
- holder.tvLastModifyTime = (TextView) view
- .findViewById(R.id.tv_record_time);
- holder.tvCurrentPlayTime = (TextView) view
- .findViewById(R.id.tv_current_play_time);
- holder.tvTotalTime = (TextView) view.findViewById(R.id.tv_total_time);
- holder.sb = (MySeekBar) view.findViewById(R.id.pb_play);
- holder.layout = (LinearLayout) view
- .findViewById(R.id.play_progress_info);
- updateData(itemIndex, holder, item);
- }
- }
自定义一个adapter继承BaseAdapter,写一个如上的方法,要更新数据时,不要调用notifyDataSetChanged()方法,调用上面的方法,即可做到更新单个item
这个艹蛋的问题,纠结了我好久。总算搞定了。。。