您的位置:首页 > 移动开发 > Android开发

Android 线程池及多线程下载,Progressbar动态更新以及文件保存sd卡

2015-10-23 09:57 441 查看
最近研究了android 多线程下载的用法,写了一个小demo,总结一下学习知识和分享一下学习经验吧。

线程池代码为:ThreadPool.java

public final class ThreadPool {
// 线程池中默认线程的个数为5
private static int worker_num = 5;
// 工作线程
private WorkThread[] workThreads;

// 任务队列,作为一个缓冲,List线程不安全
private List<Runnable> taskQueue = new LinkedList<Runnable>();

private static ThreadPool threadPool;

// 创建具有默认线程个数的线程池
private ThreadPool() {
this(5);
}

// 创建线程池,worker_num为线程池中工作线程的个数
private ThreadPool(int worker_num) {
ThreadPool.worker_num = worker_num;
workThreads = new WorkThread[worker_num];
for (int i = 0; i < worker_num; i++) {
workThreads[i] = new WorkThread();
workThreads[i].start();// 开启线程池中的线程
}
}

// 单态模式,获得一个默认线程个数的线程池
public static ThreadPool getThreadPool() {
return getThreadPool(ThreadPool.worker_num);
}

// 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
// worker_num<=0创建默认的工作线程个数
public static ThreadPool getThreadPool(int worker_num1) {
if (threadPool == null)
threadPool = new ThreadPool(worker_num1);
return threadPool;
}

// 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
public void addTask(Runnable task) {
synchronized (taskQueue) {
taskQueue.add(task);
taskQueue.notifyAll();
}
}

// 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
public void destroy() {
while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 工作线程停止工作,且置为null
for (int i = 0; i < worker_num; i++) {
workThreads[i].stopWorker();
workThreads[i] = null;
}
threadPool = null;
taskQueue.clear();// 清空任务队列
}

/**
* 内部类,工作线程
*/
private class WorkThread extends Thread {
// 该工作线程是否有效,用于结束该工作线程
private boolean isRunning = true;

/*
* 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
*/
@Override
public void run() {
Runnable r = null;
while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了
synchronized (taskQueue) {
while (isRunning && taskQueue.isEmpty()) {// 队列为空
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!taskQueue.isEmpty())
r = taskQueue.remove(0);// 取出任务
}
if (r != null) {
r.run();// 执行任务
}
r = null;
}
}

// 停止工作,让该线程自然执行完run方法,自然结束
public void stopWorker() {
isRunning = false;
}
}
}


此内容为引用别人写的代码,拿来主义时代就是这样!

好了,现在来看下下载文件的代码吧:

public class PoolRunnable implements Runnable{

private static final String TAG = "PoolRunnable";
private static final String FILE_PATH = "/Sid/download/";
private String urlString;
private int flag; //针对多个任务下载时,区别不同的任务
private File savePath;
private DownLoadBackListener listener;

public PoolRunnable(String url, int flag) {
urlString = url;
this.flag = flag;
}

public void setDownLoadListener(DownLoadBackListener ls) {
listener = ls;
}

@Override
public void run() {
// TODO Auto-generated method stub
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(urlString);
try {
HttpResponse response = client.execute(get);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
InputStream is = response.getEntity().getContent();
long length = response.getEntity().getContentLength();
boolean isOk = getSavePath(length);
if(!isOk) {
listener.downFaile("Not enough storage space", flag);
return;
}
Log.i(TAG, "flag:"+flag+"savePath:"+savePath);
OutputStream os = new FileOutputStream(savePath);
byte[] buffer = new byte[1024];
int count = 0;
long total = 0;
while((count = is.read(buffer)) != -1) {
os.write(buffer, 0, count);
total += count;
listener.downLoadProgress((int)(total*100/length), flag);
}
is.close();
os.close();
listener.downLoadOver(savePath.getAbsolutePath(), flag);
} else listener.downFaile(""+response.getStatusLine().getStatusCode(), flag);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
listener.downFaile(e.getMessage(), flag);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
listener.downFaile(e.getMessage(), flag);
}
}
/**
* 检测是否有sd卡,以及是否有足够的存储空间
* @param length
* @return
*/
public synchronized boolean getSavePath(long length) {
String basePath;
String name = urlString.substring(urlString.lastIndexOf("/"));
if(Environment.getExternalStorageState().endsWith(Environment.MEDIA_MOUNTED) &&
isAvailableSpac(Environment.getExternalStorageDirectory().getAbsolutePath(), length)) {

basePath = Environment.getExternalStorageDirectory().getAbsolutePath();
savePath = checkSavePath(basePath, name);
} else if(isAvailableSpac(Environment.getRootDirectory().getAbsolutePath(), length)){
basePath = Environment.getRootDirectory().getAbsolutePath();
savePath = checkSavePath(basePath, name);
} else return false;
File baseFile = new File(basePath + FILE_PATH);
baseFile.mkdirs();
try {
savePath.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
/**
* 当有多个同样的文件存在时,按序号存储
*/
public synchronized File checkSavePath(String base, String name) {
savePath = new File(base + FILE_PATH + name);
if(savePath.exists()) {
name = name.substring(0, name.indexOf("."));
Log.i(TAG, "name:"+name);
for (int i = 1; i < Integer.MAX_VALUE; i++) {
String last = name +"("+i+").apk";
savePath = new File(base + FILE_PATH + last);
if(!savePath.exists()) break;
}
}
return savePath;
}
/**
* 判断是否有足够的存储空间
* @param path 文件保存地址
* @param size 要保存的文件大小
* @return
*/
@SuppressWarnings("deprecation")
public boolean isAvailableSpac(String path, long size) {
StatFs statFs = new StatFs(path);
long blockSize = statFs.getBlockSize();
long blocks = statFs.getAvailableBlocks();
long availableSpare = blocks * blockSize;
Log.i("TAG", "剩余空间availableSpare = " + availableSpare);
if (availableSpare > size) {
return true;
}
return false;
}

/**
* 下载结果回馈接口
* @author user
*
*/
public interface DownLoadBackListener {
//下载进行的时候,返回进度
public void downLoadProgress(int progress, int flag);
//下载完成时调用
public void downLoadOver(String success, int flag);
//下载失败时调用
public void downFaile(String faile, int flag);
}

}


好了,干实事的就是以上这些代码了,下面看一下怎么调用他们吧:

ThreadPool pool = ThreadPool.getThreadPool(3);
barOne = (ProgressBar) findViewById(R.id.pool_progressBar1);
barTwo = (ProgressBar) findViewById(R.id.pool_progressBar2);
barThree = (ProgressBar) findViewById(R.id.pool_progressBar3);
barFour = (ProgressBar) findViewById(R.id.pool_progressBar4);
barFive = (ProgressBar) findViewById(R.id.pool_progressBar5);

PoolRunnable oneRun = new PoolRunnable(DOWNLOAD_PATH, 1);
PoolRunnable twoRun = new PoolRunnable(DOWNLOAD_PATH, 2);
PoolRunnable threeRun = new PoolRunnable(DOWNLOAD_PATH, 3);
PoolRunnable fourRun = new PoolRunnable(DOWNLOAD_PATH, 4);
PoolRunnable fiveRun = new PoolRunnable(DOWNLOAD_PATH, 5);
oneRun.setDownLoadListener(this);
twoRun.setDownLoadListener(this);
threeRun.setDownLoadListener(this);
fourRun.setDownLoadListener(this);
fiveRun.setDownLoadListener(this);

pool.addTask(oneRun);
pool.addTask(twoRun);
pool.addTask(threeRun);
pool.addTask(fourRun);
pool.addTask(fiveRun);


下载回调接口的实现:

@Override
public void downLoadProgress(int progress, int flag) {
// TODO Auto-generated method stub
switch (flag) {
case 1:
barOne.setProgress(progress);
break;
case 2:
barTwo.setProgress(progress);
break;
case 3:
barThree.setProgress(progress);
break;
case 4:
barFour.setProgress(progress);
break;
case 5:
barFive.setProgress(progress);
break;
default:
break;
}
}

@Override
public void downLoadOver(String success, int flag) {
// TODO Auto-generated method stub
Log.i(TAG, "flag:"+flag+";success:"+success);
}

@Override
public void downFaile(String faile, int flag) {
// TODO Auto-generated method stub
Log.i(TAG, "flag:"+flag+";success:"+faile);
}


具体方法的代码,还是要看自己想要处理的事情了。

好了就这么多了,有需要的下载demo看一下效果吧 ^~^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息