Android 线程池及多线程下载,Progressbar动态更新以及文件保存sd卡
2015-10-23 09:57
441 查看
最近研究了android 多线程下载的用法,写了一个小demo,总结一下学习知识和分享一下学习经验吧。
线程池代码为:ThreadPool.java
此内容为引用别人写的代码,拿来主义时代就是这样!
好了,现在来看下下载文件的代码吧:
好了,干实事的就是以上这些代码了,下面看一下怎么调用他们吧:
下载回调接口的实现:
具体方法的代码,还是要看自己想要处理的事情了。
好了就这么多了,有需要的下载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看一下效果吧 ^~^
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories