Android ListView 自定义ITEM 为 进度条 按钮,进度条实时刷新
昨天要做一个MP3多任务下载的下载管理功能,要把每个下载任务放到一个ITEM中,下载所以就会有进度条,为了可以手动开始暂停等操作,又在进度条下面增加了一个按钮,默认下载任务全部从数据库中读取,点击一个按钮,就开始一个下载任务,进度条实时更新。
download.xml
?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:divider="#330066"
android:dividerheight="1px">
</ListView>
</LinearLayout>
download_item.xml
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns: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/title_down"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="TextView"/>
<ProgressBar
android:id="@+id/pb_down"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="30dp"
/>
<Button
android:id="@+id/bt_down"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始下载"/>
</LinearLayout>
看到很多实现的方法都是开一个线程,然后handle发送消息,handle接受到消息后,调用adapter的notifyDataSetChanged()方法来刷新LISTVIEW这里总觉得有些麻烦,操作性太差了,自己试了一天都没搞定。
要注意的是为了实现LISTVIEW里面的按钮事件,所以必须从BASEADAPTER派生一个类,重写GETVIEW方法,如下:
classLvButtonAdapterextendsBaseAdapter{
privateList<Map<String,Object>>mAppList;
privateLayoutInflatermInflater;
privateContextmContext;
privateString[]keyString;
privateint[]valueViewID;
publicLvButtonAdapter(Contextc,List<Map<String,Object>>appList,intresource,
String[]from,int[]to){
mAppList=appList;
mContext=c;
mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
keyString=newString[from.length];
valueViewID=newint[to.length];
System.arraycopy(from,0,keyString,0,from.length);
System.arraycopy(to,0,valueViewID,0,to.length);
}
@Override
publicintgetCount(){
returnmAppList.size();
}
@Override
publicObjectgetItem(intposition){
returnmAppList.get(position);
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicViewgetView(finalintpos,ViewconvertView,ViewGroupparent){
buttonViewHolderholder;
if(convertView!=null){
holder=(buttonViewHolder)convertView.getTag();
}else{
convertView=mInflater.inflate(R.layout.download_item,null);
holder=newbuttonViewHolder();
holder.muiscName=(TextView)convertView.findViewById(valueViewID[0]);
holder.pb=(ProgressBar)convertView.findViewById(valueViewID[1]);
holder.button=(Button)convertView.findViewById(valueViewID[2]);
convertView.setTag(holder);
}
System.out.println("current_pos:"+pos);
pb_list.add(holder.pb);
bt_list.add(holder.button);
Map<String,Object>appInfo=mAppList.get(pos);
if(appInfo!=null){
Stringaname=(String)appInfo.get(keyString[0]);
holder.muiscName.setText(aname);
holder.button.setOnClickListener(newOnClickListener()
{
@Override
publicvoidonClick(Viewv){
//TODOAuto-generatedmethodstub
System.out.println("currentpb:"+pos);
ProgressBarpb=pb_list.get(pos);
Buttonbt=bt_list.get(pos);
if(bt.getText().toString().equals("开始下载")
||bt.getText().toString()=="开始下载"){
bt.setText("正在下载");
Object[]obj=queryItem(dbHelper,pos+1);
pb.setMax(Integer.parseInt(String.valueOf(obj[1])));
intsize=Integer.parseInt(String.valueOf(obj[1]));
Stringpath=String.valueOf(obj[0]);
Stringname=String.valueOf(obj[2]);
download(bt,pb,pos,path+".mp3",name);
}
});
}
returnconvertView;
}
}
注意在getView中测试输出ITEM位置,发现在加载LISTVIEW的时候所有ITEM所在的位置
是按顺序一次性显示出来的,这意味着GETVIEW方法里面的任何一个控件都不是你点击按钮所得到的那个ITEM,所以我用了
privateList<ProgressBar>pb_list=newArrayList<ProgressBar>();
privateList<Button>bt_list=newArrayList<Button>();
把进度条和按钮按照LISTVIEW的顺序全部添加进来。
在点击按钮的时候判断一下根据ITEM的位置查出所对应的进度条,后面按钮也一样。
下面说到重点了,SERVICE有两种启动方式START和BIND,而BINDserviceSERVICE是能直接和ACTIVITY交互的,所以在按钮点击事件中直接调用SERVICE的下载方法,把进度条作为参数传递到SERVICE中,在SERVICE中会为每个按钮事件开启一条线程来处理一个下载任务。
下面是downloadservice中的部分代码
publicvoiddownloader(Buttonbt,ProgressBarpb,intindex,Stringurl,Stringsavepath,Stringfilename){
try{
URLur=newURL(url);
System.out.println(ur);
HttpURLConnectionconn=(HttpURLConnection)ur.openConnection();
conn.connect();
fileSize=conn.getContentLength();
Log.e("length",String.valueOf(fileSize));
Filefile=newFile(savepath+"/"+filename+".mp3");
DownLoadThreadthread=newDownLoadThread(bt,pb,index,fileSize,file,conn,filename);
thread.start();
}catch(Exceptione){
e.printStackTrace();
}
}
classDownLoadThreadextendsThread{
publicDownLoadThread(){
}
privateintfileSize;
privateFilefile;
privateHttpURLConnectionconn;
privateDownloadInfoinfo;
privateProgressBarpb;
privateButtonbt;
privateintindex;
privateStringfilename;
publicDownLoadThread(Buttonbt,ProgressBarpb,intindex,intfileSize,Filefile,HttpURLConnectionconn,Stringfilename){
this.fileSize=fileSize;
this.file=file;
this.conn=conn;
this.index=index;
this.pb=pb;
this.bt=bt;
this.filename=filename;
}
inti=0;
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
BufferedReaderbr=null;
BufferedWriterbw=null;
MyMapcache=MyMap.getInstance();
try{
InputStreamins=conn.getInputStream();
FileOutputStreamfos=newFileOutputStream(file);
br=newBufferedReader(newInputStreamReader(ins));
bw=newBufferedWriter(newOutputStreamWriter(fos));
byte[]buffer=newbyte[64];
intj=0;
while((j=ins.read(buffer))!=-1){
i+=j;
fos.write(buffer,0,j);
pb.setProgress(i);
if(i==fileSize){
Intentintent=newIntent("com.download.service");
intent.putExtra("index",index);
intent.putExtra("name",filename);
intent.putExtra("current_pos",i);
sendBroadcast(intent);
}
}
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
在RUN方法中直接设置进度条的进度即可实现。