使用Thread打造上传下载器

639 阅读3分钟

项目中常常需要上传图片、帖子或者用户下载apk更新应用等等,因为上传过程中需要保存一些状态,比如进度条、发送状态(成功、失败、重发、停止)等状态,所以需要打造一个上传下载器。刚刚开始的时候的想法是重写thread,在里面保存这些状态,后来考虑到用户需要频繁的发帖和上传图片等等而且考虑到用户可以并发做这些任务,所以就改用线程池来实现上传下载器。废话不多说,马上带你打造上传下载器。

新建一个上传下载管理器ThreadManager

private int total=100;//进度条更新总进度

private Handler mHandler;//线程间通信的handler机制

private ArrayList<Info> mInfos;;//信息存储队列

private ThreadManagerListener mListener;//进度回调

private static ThreadManager mThreadManager;//上传下载器的实例

private ExecutorService mExecutorService;//线程池

上传下载器需要使用单例模式,不需要频繁创建这个实例来消耗内存

private ThreadManager(){

if(mHandler==null){

mHandler=newHandler();

}

if(mExecutorService==null){

mExecutorService= Executors.newFixedThreadPool(3);

}}

public static ThreadManager getInstance(){

if(mThreadManager==null){

synchronized(ThreadManager.class){

if(mThreadManager==null){

mThreadManager=newSpeakThreadManager();

}}}

mThreadManager;

}

状态信息类,可以放到管理器中作为内部类也可以作为外部类,用户需要什么状态的信息就存储在这里就行了,主要看你需要什么信息

public static class Info{

private int id;

public String content;

public int code=0;//状态返回码

public String message="正在发送";//提示信息

public UploadManager.MultiUploadDataimgData;//图片信息

public boolean istop=false;

public boolean isprogress=false;

public boolean updateSpeakImage=false;

public boolean isReSpeakThread=false;

public int progressSize=5;//发送进度

public int uploadSize=0;//更新进度

public boolean isFail=false;

public int len=0;//图片大小

public int size=0;//已经发送的进度

}

管理器中信息存储队列,主要的作用是确保每个线程中对应一个info状态存储信息

发送数据加入到队列中

public void addInfo(Info info){

if(mInfos==null){

mInfos=newArrayList<Info>();

}

mInfos.add(info);

}

根据id获取你需要的发送数据

public ArrayList<Info> getReleaseThreadInfo(int mId){

Info releInfo = null;

if(mInfos!=null&&mInfos.size() >0){

for(Info mInfo :mInfos)

{

if(mInfo.id== mId){

releInfo = mInfo;

}}}

return releInfo;

}  

//发送成功或者取消发送之后调用,移除已经存在的info

public boolean removeArrayInfo(Info info){

boolean flag =false;

if(mInfos!=null&&mInfos.size() >0){

if(mInfos.contains(info)){

mInfos.remove(info);

flag =true;

}}

if(mInfos!=null&&mInfos.size() <=0){

mInfos.clear();

}

return flag;

}

监控状态回调

public interface ThreadManagerListener{

public void onprogress(int total, int progressSize,Info info);

public void finish(ResultMessage info,Info info);

}

public void setThreadManagerListener(Info info,ThreadManagerListener l){

this.mListener= l;

startThreak(info);//开启耗时任务操作

}

//更新进度

private void updateProgress(final intuploadSize, final Info info){

if(mListener!=null){

mHandler.post(newRunnable(){

@Override

public voidrun(){

mListener.onprogress(total,uploadSize,info);//更新进度

}

});

//上传最终状态

private void uploadFinish(final ResultMessage result, final Info info){

if(mListener!=null){

mHandler.post(newRunnable(){

public voidrun(){

if(result!=null){

mListener.finish(result,info);

}else{

ResultMessage post =newResultMessage();

post.code= -1;

post.msg="发布失败";

mListener.finish(post,info);

}}});

}}

下面看startSpeakThreak方法,主要是在线程池中做上传下载的耗时任务,如果需要更新进度条的话直接调用updateProgress方法,上传下载任务完成需要调用uploadFinish方法,把需要实现的逻辑放到里面执行就可以了,由于这个方法是开启子线程的,所以需要更新ui的操作需要调用handler来更新。

private void startSpeakThreak(final Info info){

mExecutorService.submit(newRunnable(){

@Override

public void run(){

//这里实现耗时任务的逻辑

try{

}catch(Exception e){

e.printStackTrace();

}}});

}

使用的话只需要将发送的信息首先加入到发送队列releaseThread,然后再调用setThreadManagerListener方法设置回调就可以了。

这里主要是考虑到并发的情况,使用了线程池来实现,当然如果你不需要线程池也可以使用重写thread类,将存储信息放在管理类就可以了,逻辑一样的,看各自的业务需要。