android线程池介绍
来源:互联网 发布:防盗门锁芯规格 知乎 编辑:程序博客网 时间:2024/06/04 19:15
一. 使用ThreadPoolExecutor封装线程池管理类
public class ThreadPoolManager { private static ThreadPoolManager mInstance = new ThreadPoolManager(); private ThreadPoolExecutor executor; private int corePoolSize;//核心线程池数量,表示能够同时执行的任务数量 private int maximumPoolSize;//最大线程池数量, private long keepAliveTime = 1;//等待任务的存活时间 private TimeUnit unit = TimeUnit.HOURS;//存活时间的时间单位 public static ThreadPoolManager getInstance(){ return mInstance; } private ThreadPoolManager(){ //核心线程池数量的计算规则:当前设备的可用处理器核心数*2 + 1,能够让CPU得到最大效率的发挥; corePoolSize = Runtime.getRuntime().availableProcessors()*2+1; maximumPoolSize = corePoolSize;//虽然用不到,但是不能是0,否则报错 //线程池机制:领工资的机制 executor = new ThreadPoolExecutor( corePoolSize, //3 maximumPoolSize,//5,最大的线程池数量 keepAliveTime, unit, new LinkedBlockingQueue<Runnable>(),//缓冲队列,超出核心线程池的任务会被放入缓存队列中等待 Executors.defaultThreadFactory(),//创建线程的工厂类 new ThreadPoolExecutor.AbortPolicy()//当超出最大线程池数量的时候,则拒绝执行 ); } /** * 往线程池中添加任务 * @param r */ public void execute(Runnable r){ if(r!=null){ executor.execute(r); } } /** * 从线程池中移除任务 * @param r */ public void remove(Runnable r){ if(r!=null){ executor.remove(r); } }}
二. 定义DownloadManager,定义下载状态常量
public class DownloadManager { public static final int STATE_NONE = 0;//未下载的状态 public static final int STATE_DOWNLOADING = 1;//下载中的状态 public static final int STATE_PAUSE = 2;//暂停的状态 public static final int STATE_WAITING = 3;//等待中的状态,任务对象已经创建,但是run方法没有执行 public static final int STATE_FINISH = 4;//下载完成的状态 public static final int STATE_ERROR = 5;//下载出错的状态}
三. 将DownloadManager设计为单例模式
private static DownloadManager mInstance = new DownloadManager();public static DownloadManager getInstance(){ return mInstance;}private DownloadManager(){}
四. 定义下载相关的方法,如download方法,pause方法等
public void download(){}public void pause(){}public void installApk(){}public void registerDownloadObserver(DownloadObserver downloadObserver){ if(!observerList.contains(downloadObserver)){ observerList.add(downloadObserver); }}/** * 从集合中移除下载观察者 * @param downloadObserver */public void unregisterDownloadObserver(DownloadObserver downloadObserver){ if(observerList.contains(downloadObserver)){ observerList.remove(downloadObserver); }}/** * 下载状态和进度改变的监听器 * @author Administrator * */public interface DownloadObserver{ /** * 下载状态改变的回调 */ void onDownloadStateChange(DownloadInfo downloadInfo); /** * 下载进度改变的回调 */ void onDownloadProgressChange(DownloadInfo downloadInfo);}
五. 定义DownloadInfo类,用来封装每个下载任务的数据
/** * 封装的是下载任务相关的数据,包括标识,进度,状态,文件保存路径等 * */public class DownloadInfo { private long id;// 下载任务的唯一标识 private int state;// 下载状态 private long currentLength;// 已经下载的长度 private long size;// 总大小 private String downloadUrl;// 下载地址 private String path;// apk文件的保存的绝对路径 /** * 使用AppInfo创建DownloadInfo * @return */ public static DownloadInfo create(AppInfo appInfo) { DownloadInfo downloadInfo = new DownloadInfo(); downloadInfo.setId(appInfo.getId()); downloadInfo.setSize(appInfo.getSize()); downloadInfo.setDownloadUrl(appInfo.getDownloadUrl()); downloadInfo.setState(DownloadManager.STATE_NONE);// 初始化状态 downloadInfo.setCurrentLength(0); // /mnt/sdcard/包名/download/有缘网.apk downloadInfo.setPath(DownloadManager.DOWNLOAD_DIR + File.separator + appInfo.getName() + ".apk"); return downloadInfo; }}
六. 实现download方法
先根据app的id获取对象的任务信息,即DownloadInfo,如果没有则通过静态方法创建,然后存入map中
DownloadInfo downloadInfo = downloadInfoMap.get((int) appInfo.getId());if(downloadInfo==null){ //说明该任务从来没有下载过 downloadInfo = DownloadInfo.create(appInfo); //将downloadInfo存入downloadInfoMap中 downloadInfoMap.put((int) downloadInfo.getId(), downloadInfo);}
获取state,判断state是否可以进行下载,如果可以则创建DownloadTask,并交给线程池执行
int state = downloadInfo.getState();if(state==STATE_NONE || state==STATE_PAUSE || state==STATE_ERROR){ //说明可以进行下载了,那么就可以创建DownloadTask,交给线程池管理 DownloadTask downloadTask = new DownloadTask(downloadInfo); //更新下载任务对应的state downloadInfo.setState(STATE_WAITING);//更新状态为等待中 //通知监听器状态更改了 notifyDownloadStateChange(downloadInfo); //3.将DownloadTask交给线程池管理 ThreadPoolManager.getInstance().execute(downloadTask);}
实现DownloadTask,在run方法的开始就将状态置为下载中
//4.run方法执行就将state设置downloadingdownloadInfo.setState(STATE_DOWNLOADING);//更新状态为等待中//通知监听器状态更改notifyDownloadStateChange(downloadInfo);
判断下载类型,进行相应的下载
//5.判断下载类型:a.从头下载 b.断点下载HttpUtil.HttpResult httpResult = null;File file = new File(downloadInfo.getPath());if(!file.exists() || file.length()!=downloadInfo.getCurrentLength()){ //需要从头下载的情况 file.delete();//删除无效文件 downloadInfo.setCurrentLength(0);//清空currentLength String url = String.format(Url.Download,downloadInfo.getDownloadUrl()); httpResult = HttpEngine.getInstance().download(url);}else { //需要断点下载的情况 String url = String.format(Url.Break_Download,downloadInfo.getDownloadUrl(),downloadInfo.getCurrentLength()); httpResult = HttpEngine.getInstance().download(url);}
下载类使用HttpEngine,里面封装的是HttpClient, 重在理解下载逻辑的实现思路;
获取到HttpResult后,则可以开始读取流下载文件了,并且读取的过程中要注意通知进度更新
//6.读取流,写入文件 if(httpResult!=null ){ //说明成功的请求到了文件数据 InputStream is = httpResult.getInputStream(); FileOutputStream fos = null; try { fos = new FileOutputStream(file,true); byte[] buffer = new byte[1024*8];//8k的缓冲区 int len = -1; while((len=is.read(buffer))!=-1 && downloadInfo.getState()==STATE_DOWNLOADING){ fos.write(buffer, 0, len);//写文件 //更新currentLength downloadInfo.setCurrentLength(downloadInfo.getCurrentLength()+len); //通知监听器下载进度更新 notifyDownloadProgressChange(downloadInfo); } } catch (Exception e) { e.printStackTrace(); Log.e(TAG, "run: "+e.getLocalizedMessage() ); //属于下载失败的情况 processDownloadError(file); }finally{ //关闭链接和流 httpResult.close(); try { if(fos!=null)fos.close(); } catch (IOException e) { e.printStackTrace(); } } //7.代码走到这里:a.下载完成 b.暂停 if(file.length()==downloadInfo.getSize() && downloadInfo.getState()==STATE_DOWNLOADING){ //说明下载完成了 downloadInfo.setState(STATE_FINISH); notifyDownloadStateChange(downloadInfo); }else if (downloadInfo.getState()==STATE_PAUSE) { notifyDownloadStateChange(downloadInfo); } }else { //说明请求文件数据失败 processDownloadError(file); }
七. 实现暂停方法,取出DownloadTask,将其状态更改为暂停即可
/** * 暂停的方法 */public void pause(AppInfo appInfo){ DownloadInfo downloadInfo = getDownloadInfo(appInfo); if(downloadInfo!=null){ //将当前downloadINfo的state设置为pause downloadInfo.setState(STATE_PAUSE);//更改状态 notifyDownloadStateChange(downloadInfo); }}
八. 实现安装apk的方法
/** * 安装app的方法 */public void installApk(AppInfo appInfo){ DownloadInfo downloadInfo = getDownloadInfo(appInfo); if(downloadInfo!=null){ /*<action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <data android:scheme="file" /> <data android:mimeType="application/vnd.android.package-archive" />*/ Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//开启新的任务栈来存放新的Activity intent.setDataAndType(Uri.parse("file://"+downloadInfo.getPath()),"application/vnd.android.package-archive"); GooglePlayApp.context.startActivity(intent); }}
九. 编写AppDownloadHolder类,完成下载功能
在initHolderView中注册下载监听器
// 注册下载监听器DownloadManager.getInstance().registerDownloadObserver(this);
处理点击事件,点击的时候根据当前的state进行相应的操作
public void onClick(View v) {switch (v.getId()) {case R.id.btn_download: DownloadInfo downloadInfo = DownloadManager.getInstance() .getDownloadInfo(appInfo); if (downloadInfo == null) { // 说明从来没有下载过,那么就去下载 DownloadManager.getInstance().download(appInfo); } else { // 说明下载过,那么应该根据state来判断 if (downloadInfo.getState() == DownloadManager.STATE_DOWNLOADING || downloadInfo.getState() == DownloadManager.STATE_WAITING) { // 应该暂停 DownloadManager.getInstance().pause(appInfo); } else if (downloadInfo.getState() == DownloadManager.STATE_PAUSE || downloadInfo.getState() == DownloadManager.STATE_ERROR) { // 应该继续下载,或者重新下载 DownloadManager.getInstance().download(appInfo); } else if (downloadInfo.getState() == DownloadManager.STATE_FINISH) { // 应该安装 DownloadManager.getInstance().installApk(appInfo); } } break;}
}
根据下载状态和下载进度的更新UI
/** * 下载进度改变 */@Overridepublic void onDownloadProgressChange(final DownloadInfo downloadInfo) { if(appInfo==null || appInfo.getId()!=downloadInfo.getId()){ //如果当前的app和正在下载的app不是同一个 return; } // 获取百分比 12.3333 float percent = downloadInfo.getCurrentLength() * 100f / downloadInfo.getSize(); // 将进度设置给进度条 pb_progress.setProgress((int) percent); // 将百分比设置给下载按钮 btn_download.setBackgroundResource(0);// 移除按钮的背景 btn_download.setText((int) percent + "%");}@Overridepublic void onDownloadStateChange(final DownloadInfo downloadInfo) { updateDownloadState(downloadInfo);}/** * 根据当前的下载状态来更新UI * @param downloadInfo */public void updateDownloadState(final DownloadInfo downloadInfo) { if(appInfo==null || appInfo.getId()!=downloadInfo.getId()){ //如果当前的app和正在下载的app不是同一个 return; } switch (downloadInfo.getState()) { case DownloadManager.STATE_PAUSE: btn_download.setText("继续下载"); // 显示下载的进度条 // 获取百分比 12.3333 float percent = downloadInfo.getCurrentLength() * 100f / downloadInfo.getSize(); // 将进度设置给进度条 pb_progress.setProgress((int) percent); btn_download.setBackgroundResource(0);// 移除按钮的背景 break; case DownloadManager.STATE_FINISH: btn_download.setText("安装"); break; case DownloadManager.STATE_WAITING: btn_download.setText("等待中"); break; case DownloadManager.STATE_ERROR: btn_download.setText("出错,重下"); break; }}
在绑定数据的时候,需要根据当前的state初始化UI
public void bindData(AppInfo appInfo) { this.appInfo = appInfo; // 刚进来的时候如果是暂停的则会导致UI有错误,需要手动获取当前的state进行更新 DownloadInfo downloadInfo = DownloadManager.getInstance() .getDownloadInfo(appInfo); if (downloadInfo != null) { updateDownloadState(downloadInfo); }}
0 0
- android线程池介绍
- Android线程池介绍
- Android 线程池基础介绍
- Android获取线程池的方法介绍
- Android 线程 实例介绍
- Android-线程-简单介绍
- Android 线程 基本用法介绍
- Android—四大线程池的使用介绍
- JAVA线程池介绍
- ThreadPoolExecutor 线程池 介绍
- 线程池的介绍
- Java线程池介绍
- Java线程池介绍
- Java线程池介绍
- java 线程池介绍
- Java线程池介绍
- Elasticsearch线程池介绍
- 线程池介绍
- RC电路
- 对CSS的初步认识
- Learning Scrapy 笔记(1)
- Python_cmd的各种实现方法及优劣(subprocess.Popen, os.system和commands.getstatusoutput)
- 第一个C++程序。输入输出
- android线程池介绍
- 使用procedure analyse()分析mysql给出的关于表结构的优化建议
- Missing Number
- iOS 加密总结(Base64 、DES、MD5)持续更新
- Spring MVC 中使用H5接口FormData上传文件实例
- 启动优化 让app秒开
- logback配置详解
- FMDB详解
- 小伙的java之旅——泛型