最近在做一个单线程多任务的断点排队下载的功能,网上确实有很多这样的demo。但是呢我发现大部分网上的demo都是很些不完整的要么就是有缺陷的,可能是我还没找到。今天我给大家带来的一个功能完整的并且可以多界面刷新,就比如:我当前界面点了下载放后台下载了,退出了当前界面在进来网上很多这样demo都没做继续更新界面。并且还做了排队。
首先我们先制定下计划:
1、我们做的是断点下载,断点下载肯定是需要记录当前下载的进度和文件总大小的。这个当然是放在数据库里面最好,当然肯定会是异步来操作数据库,这里我们就需要用到线程锁synchronized来控制了。
2、多任务是指可以多个任务一起下载,但是我们是有排队机制的,所以当前任务只是一个任务在下载,其他的按点击顺序排队执行,这里我们就需要写一个下载管理器来管理整个下载团队,当暂停和取消都是需要把队列排队给去掉的,当然我这里是用的线程池(ThreadPoolExecutor)来管理线程的。
3、还需要做到多界面刷新,我这里是通过注册一个下载监听来做的,所有的监听都放在map集合里面,已id为key来进行保存,每次需要回调监听的时候都是通过map里面去找,所以销毁的时候需要去注销下所有的监听,然而每次去新的界面只要注册了下载监听,我又可以再map里面找到你新注册的监听从而来进行新的回调。
话不多说,请看效果:
接下来我们来分析代码:
首先我们需要创建数据库、创建表、创建文件夹、所需的操作表的代码、以及下载所需要的Bean(这种初始化操作就不在这里详细做描述)
现在我们说重点,线程池的管理
由于我们是单线程,所以线程池里面同时执行的线程只需为1就可以,(意思就是说当前线程执行的只有1条线程,当前的线程还没执行完毕就把后面添加进来的线程进行有序排序<先来后到顺序>)。并且还可以拿到排队中并还没执行的线程,这样我们就可以做很多事了。
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.down.executors; <span class="hljs-keyword">import</span> java.util.concurrent.Executors; <span class="hljs-keyword">import</span> java.util.concurrent.LinkedBlockingQueue; <span class="hljs-keyword">import</span> java.util.concurrent.ThreadPoolExecutor; <span class="hljs-keyword">import</span> java.util.concurrent.TimeUnit; <span class="hljs-keyword">import</span> java.util.concurrent.ThreadPoolExecutor.AbortPolicy; <span class="hljs-javadoc">/** * 线程池工具 */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DownLoadExecutor</span> {</span> <span class="hljs-javadoc">/** 请求线程池队列,同时允许1个线程操作 */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> ThreadPoolExecutor mPool ; <span class="hljs-comment">//当线程池中的线程小于mCorePoolSize,直接创建新的线程加入线程池执行任务</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> mCorePoolSize = <span class="hljs-number">1</span>; <span class="hljs-comment">//最大线程数</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> mMaximumPoolSize = <span class="hljs-number">1</span>; <span class="hljs-comment">//线程执行完任务后,且队列中没有可以执行的任务,存活的时间,后面的参数是时间单位</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">long</span> mKeepAliveTime = <span class="hljs-number">5</span>L; <span class="hljs-javadoc">/** 执行任务,当线程池处于关闭,将会重新创建新的线程池 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">execute</span>(Runnable run) { <span class="hljs-keyword">if</span> (run == <span class="hljs-keyword">null</span>) { <span class="hljs-keyword">return</span>; } <span class="hljs-keyword">if</span> (mPool == <span class="hljs-keyword">null</span> || mPool.isShutdown()) { <span class="hljs-comment">//参数说明</span> <span class="hljs-comment">//当线程池中的线程小于mCorePoolSize,直接创建新的线程加入线程池执行任务</span> <span class="hljs-comment">//当线程池中的线程数目等于mCorePoolSize,将会把任务放入任务队列BlockingQueue中</span> <span class="hljs-comment">//当BlockingQueue中的任务放满了,将会创建新的线程去执行,</span> <span class="hljs-comment">//但是当总线程数大于mMaximumPoolSize时,将会抛出异常,交给RejectedExecutionHandler处理</span> <span class="hljs-comment">//mKeepAliveTime是线程执行完任务后,且队列中没有可以执行的任务,存活的时间,后面的参数是时间单位</span> <span class="hljs-comment">//ThreadFactory是每次创建新的线程工厂</span> mPool = <span class="hljs-keyword">new</span> ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.MILLISECONDS, <span class="hljs-keyword">new</span> LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), <span class="hljs-keyword">new</span> AbortPolicy()); } mPool.execute(run); } <span class="hljs-javadoc">/** 取消线程池中某个还未执行的任务 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">cancel</span>(Runnable run) { <span class="hljs-keyword">if</span> (mPool != <span class="hljs-keyword">null</span> && (!mPool.isShutdown() || mPool.isTerminating())) { <span class="hljs-keyword">return</span> mPool.getQueue().remove(run); }<span class="hljs-keyword">else</span>{ <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; } } <span class="hljs-javadoc">/** 查看线程池中是否还有某个还未执行的任务 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">contains</span>(Runnable run) { <span class="hljs-keyword">if</span> (mPool != <span class="hljs-keyword">null</span> && (!mPool.isShutdown() || mPool.isTerminating())) { <span class="hljs-keyword">return</span> mPool.getQueue().contains(run); } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; } } <span class="hljs-javadoc">/** 立刻关闭线程池,并且正在执行的任务也将会被中断 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">stop</span>() { <span class="hljs-keyword">if</span> (mPool != <span class="hljs-keyword">null</span> && (!mPool.isShutdown() || mPool.isTerminating())) { mPool.shutdownNow(); } } <span class="hljs-javadoc">/** 平缓关闭单任务线程池,但是会确保所有已经加入的任务都将会被执行完毕才关闭 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">shutdown</span>() { <span class="hljs-keyword">if</span> (mPool != <span class="hljs-keyword">null</span> && (!mPool.isShutdown() || mPool.isTerminating())) { mPool.shutdownNow(); } } }</code>
这里是取名为观察者,也就是监听回调
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.down.executors; <span class="hljs-keyword">import</span> com.down.bean.DownLoadBean; <span class="hljs-javadoc">/** * 观察者 */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">DownLoadObserver</span> {</span> <span class="hljs-javadoc">/**准备下载*/</span> <span class="hljs-keyword">void</span> onPrepare(DownLoadBean bean); <span class="hljs-javadoc">/** 开始下载 */</span> <span class="hljs-keyword">void</span> onStart(DownLoadBean bean); <span class="hljs-javadoc">/** 下载中 */</span> <span class="hljs-keyword">void</span> onProgress(DownLoadBean bean); <span class="hljs-javadoc">/** 暂停 */</span> <span class="hljs-keyword">void</span> onStop(DownLoadBean bean); <span class="hljs-javadoc">/** 下载完成 */</span> <span class="hljs-keyword">void</span> onFinish(DownLoadBean bean); <span class="hljs-javadoc">/** 下载失败 */</span> <span class="hljs-keyword">void</span> onError(DownLoadBean bean); <span class="hljs-javadoc">/** 删除成功 */</span> <span class="hljs-keyword">void</span> onDelete(DownLoadBean bean); }</code>
现在关键部分到了,我们的下载管理器。
管理器全局操作:开始下载之前必须先注册下载监听,不然后不会回调,注册监听的时候就把监听放到map集合,开启下载的时候就把当前线程也到map集合保存,这样就简单啦,假如我需要暂停或者删除当前下载的任务,直接改变状态在下载的while循环里面直接return就可,如果是排队中的呢,则是先拿到队列中的任务线程再把线程中的bean对象里面的状态置为暂停或者删除,这样就算到它执行的时候也会直接返回(因为我的执行线程里面第一行代码就是判断是否被暂停或删除),继续执行排在他后面的任务线程。删除下载任务则是先从map集合里面通过id拿到需要删除的线程,然后把线程里面的状态改为删除,然后删除数据库,删除文件。
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.down.executors; <span class="hljs-keyword">import</span> java.io.File; <span class="hljs-keyword">import</span> java.io.FileOutputStream; <span class="hljs-keyword">import</span> java.io.IOException; <span class="hljs-keyword">import</span> java.io.InputStream; <span class="hljs-keyword">import</span> java.io.OutputStream; <span class="hljs-keyword">import</span> java.net.HttpURLConnection; <span class="hljs-keyword">import</span> java.net.URL; <span class="hljs-keyword">import</span> java.util.Map; <span class="hljs-keyword">import</span> java.util.concurrent.ConcurrentHashMap; <span class="hljs-keyword">import</span> android.annotation.SuppressLint; <span class="hljs-keyword">import</span> android.os.Handler; <span class="hljs-keyword">import</span> android.os.Looper; <span class="hljs-keyword">import</span> android.os.Message; <span class="hljs-keyword">import</span> android.util.Log; <span class="hljs-keyword">import</span> com.down.bean.DownLoadBean; <span class="hljs-keyword">import</span> com.down.uitl.DataBaseUtil; <span class="hljs-javadoc">/** * 下载管理器 */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DownLoadManager</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_NONE = -<span class="hljs-number">1</span>; <span class="hljs-javadoc">/** 开始下载 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_START = <span class="hljs-number">0</span>; <span class="hljs-javadoc">/** 等待中 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_WAITING = <span class="hljs-number">1</span>; <span class="hljs-javadoc">/** 下载中 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_DOWNLOADING = <span class="hljs-number">2</span>; <span class="hljs-javadoc">/** 暂停 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_PAUSED = <span class="hljs-number">3</span>; <span class="hljs-javadoc">/** 下载完毕 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_DOWNLOADED = <span class="hljs-number">4</span>; <span class="hljs-javadoc">/** 下载失败 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_ERROR = <span class="hljs-number">5</span>; <span class="hljs-javadoc">/** 删除下载成功 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_DELETE = <span class="hljs-number">6</span>; <span class="hljs-javadoc">/** 用于记录观察者,当信息发送了改变,需要通知他们 */</span> <span class="hljs-keyword">private</span> Map<String, DownLoadObserver> mObservers = <span class="hljs-keyword">new</span> ConcurrentHashMap<String, DownLoadObserver>(); <span class="hljs-javadoc">/** 用于记录所有下载的任务,方便在取消下载时,通过id能找到该任务进行删除 */</span> <span class="hljs-keyword">private</span> Map<String, DownLoadTask> mTaskMap = <span class="hljs-keyword">new</span> ConcurrentHashMap<String, DownLoadTask>(); <span class="hljs-javadoc">/** 全局记录当前正在下载的bean */</span> <span class="hljs-keyword">private</span> DownLoadBean down_bean; <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> DownLoadManager instance; <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DownLoadManager <span class="hljs-title">getInstance</span>() { <span class="hljs-keyword">if</span> (instance == <span class="hljs-keyword">null</span>) { instance = <span class="hljs-keyword">new</span> DownLoadManager(); } <span class="hljs-keyword">return</span> instance; } <span class="hljs-javadoc">/** 注册观察者 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerObserver</span>(String id, DownLoadObserver observer) { <span class="hljs-keyword">if</span> (!mObservers.containsKey(id)) { mObservers.put(id, observer); } } <span class="hljs-javadoc">/** 移除观察者 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">RemoveObserver</span>() { mObservers.clear(); } <span class="hljs-javadoc">/** 删除当前正在下载的任务 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">DeleteDownTask</span>(DownLoadBean bean) { <span class="hljs-keyword">if</span> (mTaskMap.containsKey(bean.id)) { <span class="hljs-comment">// 拿到当前任务</span> DownLoadTask task = mTaskMap.get(bean.id); <span class="hljs-comment">// 暂停下载任务(等于取消了该线程)</span> task.bean.downloadState = STATE_DELETE; <span class="hljs-comment">// 再更改删除界面状态(这是也调一次是怕在没下载的时候删除)</span> bean.downloadState = STATE_DELETE; notifyDownloadStateChanged(bean); <span class="hljs-comment">// 最后删除数据库数据</span> DataBaseUtil.DeleteDownLoadById(bean.id); <span class="hljs-comment">// 删除文件</span> File file = <span class="hljs-keyword">new</span> File(bean.getPath()); <span class="hljs-keyword">if</span> (file.exists()) { file.delete(); } file = <span class="hljs-keyword">null</span>; } } <span class="hljs-javadoc">/** 销毁的时候关闭线程池以及当前执行的线程,并清空所有数据和把当前下载状态存进数据库 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Destory</span>() { DownLoadExecutor.stop(); mObservers.clear(); mTaskMap.clear(); <span class="hljs-keyword">if</span> (down_bean != <span class="hljs-keyword">null</span>) { down_bean.downloadState = STATE_PAUSED; DataBaseUtil.UpdateDownLoadById(down_bean); } } <span class="hljs-javadoc">/** 当下载状态发送改变的时候回调 */</span> <span class="hljs-keyword">private</span> ExecuteHandler handler = <span class="hljs-keyword">new</span> ExecuteHandler(); <span class="hljs-javadoc">/** 拿到主线程Looper */</span> <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"HandlerLeak"</span>) <span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExecuteHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> {</span> <span class="hljs-keyword">private</span> <span class="hljs-title">ExecuteHandler</span>() { <span class="hljs-keyword">super</span>(Looper.getMainLooper()); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) { DownLoadBean bean = (DownLoadBean) msg.obj; <span class="hljs-keyword">if</span> (mObservers.containsKey(bean.id)) { DownLoadObserver observer = mObservers.get(bean.id); <span class="hljs-keyword">switch</span> (bean.downloadState) { <span class="hljs-keyword">case</span> STATE_START:<span class="hljs-comment">// 开始下载</span> observer.onStart(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_WAITING:<span class="hljs-comment">// 准备下载</span> observer.onPrepare(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DOWNLOADING:<span class="hljs-comment">// 下载中</span> observer.onProgress(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_PAUSED:<span class="hljs-comment">// 暂停</span> observer.onStop(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DOWNLOADED:<span class="hljs-comment">// 下载完毕</span> observer.onFinish(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_ERROR:<span class="hljs-comment">// 下载失败</span> observer.onError(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DELETE:<span class="hljs-comment">// 删除成功</span> observer.onDelete(bean); <span class="hljs-keyword">break</span>; } } } } <span class="hljs-javadoc">/** 当下载状态发送改变的时候调用 */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">notifyDownloadStateChanged</span>(DownLoadBean bean) { Message message = handler.obtainMessage(); message.obj = bean; handler.sendMessage(message); } <span class="hljs-javadoc">/** 开启下载,需要传入一个DownAppBean对象 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">download</span>(DownLoadBean loadBean) { <span class="hljs-comment">// 先判断是否有这个app的下载信息</span> DownLoadBean bean = DataBaseUtil.getDownLoadById(loadBean.id); <span class="hljs-keyword">if</span> (bean == <span class="hljs-keyword">null</span>) {<span class="hljs-comment">// 如果没有,则根据loadBean创建一个新的下载信息</span> bean = loadBean; DataBaseUtil.insertDown(bean); } <span class="hljs-comment">// 判断状态是否为STATE_NONE、STATE_PAUSED、STATE_ERROR、STATE_DELETE。只有这4种状态才能进行下载,其他状态不予处理</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_NONE || bean.downloadState == STATE_PAUSED || bean.downloadState == STATE_DELETE || bean.downloadState == STATE_ERROR) { <span class="hljs-comment">// 下载之前,把状态设置为STATE_WAITING,因为此时并没有产开始下载,只是把任务放入了线程池中,当任务真正开始执行时,才会改为STATE_DOWNLOADING</span> bean.downloadState = STATE_WAITING; DataBaseUtil.UpdateDownLoadById(bean); <span class="hljs-comment">// 每次状态发生改变,都需要回调该方法通知所有观察者</span> notifyDownloadStateChanged(bean); DownLoadTask task = <span class="hljs-keyword">new</span> DownLoadTask(bean);<span class="hljs-comment">// 创建一个下载任务,放入线程池</span> <span class="hljs-comment">// 线程放入map里面方便管理</span> mTaskMap.put(bean.id, task); DownLoadExecutor.execute(task); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_START || bean.downloadState == STATE_DOWNLOADING || bean.downloadState == STATE_WAITING) {<span class="hljs-comment">// 如果正在下载则暂停</span> <span class="hljs-keyword">if</span> (mTaskMap.containsKey(bean.id)) { DownLoadTask task = mTaskMap.get(bean.id); task.bean.downloadState = STATE_PAUSED; DataBaseUtil.UpdateDownLoadById(task.bean); <span class="hljs-comment">// 取消还在排队中的线程</span> <span class="hljs-keyword">if</span> (DownLoadExecutor.cancel(task)) { mObservers.get(bean.id).onStop(task.bean); } } } }</code>
下载线程:这里需要注意的事,我没有在他实时下载的时候保存他的进度,只在他断掉的时候保存,因为我觉得实时下载的时候一直操作数据库不妥,性能肯定有问题。好,这时你们就会问,假如我操作不当会导致数据库里面没有当前进度,但是注意看清楚了,我下载的时候是拿的文件当前长度而不是数据库的下载进度,其实这很好理解,文件都没了,就算你数据库里面记录的有进度,也于事无补所以说拿文件的当前长度是最合理的。当然如果文件没了,肯定得先创建文件然后下载进度肯定也是0了。
我们使用的断点下载是使用的http里面的Range属性,里面参数为当前进度-某进度,这个是支持多线程下载的,这里我们只是单线程,所以就是当前进度-文件的总进度。当然我们还得看这个服务器是否支持断点下载,有的服务器不支持断点下载,你下载下来那就是坑爹,怎么判断呢,这个http里面有返回状态码的,返回206就证明是可以断点下载的。
当然下载中途报任何崩溃都是下载失败,都是需要删除数据。还有就是记得下载完之后一定要把保存线程的map集合里面remove掉这条线程
<code class="hljs java has-numbering"> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DownLoadTask</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span> {</span> <span class="hljs-keyword">private</span> DownLoadBean bean; <span class="hljs-keyword">public</span> <span class="hljs-title">DownLoadTask</span>(DownLoadBean bean) { <span class="hljs-keyword">this</span>.bean = bean; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() { <span class="hljs-comment">// 等待中就暂停了</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_PAUSED) { bean.downloadState = STATE_PAUSED; DataBaseUtil.UpdateDownLoadById(bean); <span class="hljs-keyword">return</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_DELETE) {<span class="hljs-comment">// 等待中就删除直接回调界面,然后直接返回</span> bean.downloadState = STATE_DELETE; notifyDownloadStateChanged(bean); mTaskMap.remove(bean.id); <span class="hljs-keyword">return</span>; } bean.downloadState = DownLoadManager.STATE_START;<span class="hljs-comment">// 开始下载</span> DataBaseUtil.UpdateDownLoadById(bean); notifyDownloadStateChanged(bean); <span class="hljs-comment">// 当前下载的进度</span> <span class="hljs-keyword">long</span> compeleteSize = <span class="hljs-number">0</span>; File file = <span class="hljs-keyword">new</span> File(bean.getPath());<span class="hljs-comment">// 获取下载文件</span> <span class="hljs-keyword">if</span> (!file.exists()) { <span class="hljs-comment">// 如果文件不存在</span> bean.currentSize = <span class="hljs-number">0</span>; <span class="hljs-keyword">try</span> { file.createNewFile(); } <span class="hljs-keyword">catch</span> (IOException e) { e.printStackTrace(); } } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 如果存在就拿当前文件的长度,设置当前下载长度</span> <span class="hljs-comment">// (这样的好处就是不用每次在下载文件的时候都需要写入数据库才能记录当前下载的长度,一直操作数据库是很费资源的)</span> compeleteSize = file.length(); } <span class="hljs-keyword">try</span> { URL url = <span class="hljs-keyword">new</span> URL(bean.url); HttpURLConnection connection = (HttpURLConnection) url .openConnection(); connection.setConnectTimeout(<span class="hljs-number">30</span> * <span class="hljs-number">1000</span>); connection.setRequestMethod(<span class="hljs-string">"GET"</span>); connection.setRequestProperty(<span class="hljs-string">"Range"</span>, <span class="hljs-string">"bytes="</span> + compeleteSize + <span class="hljs-string">"-"</span> + bean.appSize); <span class="hljs-comment">// 获取的状态码</span> <span class="hljs-keyword">int</span> code = connection.getResponseCode(); <span class="hljs-comment">// 判断是否能够断点下载</span> <span class="hljs-keyword">if</span> (code == <span class="hljs-number">206</span>) { <span class="hljs-annotation">@SuppressWarnings</span>(<span class="hljs-string">"resource"</span>) OutputStream outputStream = <span class="hljs-keyword">new</span> FileOutputStream(file, <span class="hljs-keyword">true</span>); <span class="hljs-comment">// 将要下载的文件写到保存在保存路径下的文件中</span> InputStream is = connection.getInputStream(); <span class="hljs-keyword">byte</span>[] buffer = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">102400</span>]; <span class="hljs-keyword">int</span> length = -<span class="hljs-number">1</span>; <span class="hljs-comment">// 进入下载中状态</span> bean.downloadState = STATE_DOWNLOADING; DataBaseUtil.UpdateDownLoadById(bean); <span class="hljs-keyword">while</span> ((length = is.read(buffer)) != -<span class="hljs-number">1</span>) { <span class="hljs-comment">// 暂停就回调,然后直接返回</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_PAUSED) { bean.downloadState = STATE_PAUSED; DataBaseUtil.UpdateDownLoadById(bean); notifyDownloadStateChanged(bean); <span class="hljs-keyword">return</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == STATE_DELETE) {<span class="hljs-comment">// 下载的时候删除直接回调界面,然后直接返回</span> bean.downloadState = STATE_DELETE; notifyDownloadStateChanged(bean); mTaskMap.remove(bean.id); <span class="hljs-keyword">return</span>; } <span class="hljs-comment">// 把当前下载的bean给全局记录的bean</span> down_bean = bean; outputStream.write(buffer, <span class="hljs-number">0</span>, length); compeleteSize += length; <span class="hljs-comment">// 更新数据库中的下载信息</span> <span class="hljs-comment">// 用消息将下载信息传给进度条,对进度条进行更新</span> bean.currentSize = compeleteSize; notifyDownloadStateChanged(bean); } <span class="hljs-keyword">if</span> (bean.appSize == bean.currentSize) { bean.downloadState = STATE_DOWNLOADED; DataBaseUtil.UpdateDownLoadById(bean); notifyDownloadStateChanged(bean); } <span class="hljs-keyword">else</span> { bean.downloadState = STATE_ERROR; DataBaseUtil.UpdateDownLoadById(bean); notifyDownloadStateChanged(bean); bean.currentSize = <span class="hljs-number">0</span>;<span class="hljs-comment">// 错误状态需要删除文件</span> file.delete(); } } <span class="hljs-keyword">else</span> { Log.e(<span class="hljs-string">"123456"</span>, <span class="hljs-string">"不支持断点下载"</span>); } } <span class="hljs-keyword">catch</span> (IOException e) { bean.downloadState = STATE_ERROR; DataBaseUtil.UpdateDownLoadById(bean); notifyDownloadStateChanged(bean); bean.currentSize = <span class="hljs-number">0</span>;<span class="hljs-comment">// 错误状态需要删除文件</span> file.delete(); } mTaskMap.remove(bean.id); } } }</code>
监听回调:当然回调监听都是通过map集合里面来找,有就通过id回调,没有就不回调。这样就能保证你每次注册的监听回调都是最新的。达到只要注册了下载监听并且是当前下载的那条id。就能回调的到你最新注册的监听,刷新界面。当然你界面销毁的时候也要注销监听(也就是清除保存监听map的集合)。
<code class="hljs java has-numbering"> <span class="hljs-javadoc">/** 当下载状态发送改变的时候回调 */</span> <span class="hljs-keyword">private</span> ExecuteHandler handler = <span class="hljs-keyword">new</span> ExecuteHandler(); <span class="hljs-javadoc">/** 拿到主线程Looper */</span> <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"HandlerLeak"</span>) <span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExecuteHandler</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Handler</span> {</span> <span class="hljs-keyword">private</span> <span class="hljs-title">ExecuteHandler</span>() { <span class="hljs-keyword">super</span>(Looper.getMainLooper()); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) { DownLoadBean bean = (DownLoadBean) msg.obj; <span class="hljs-keyword">if</span> (mObservers.containsKey(bean.id)) { DownLoadObserver observer = mObservers.get(bean.id); <span class="hljs-keyword">switch</span> (bean.downloadState) { <span class="hljs-keyword">case</span> STATE_START:<span class="hljs-comment">// 开始下载</span> observer.onStart(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_WAITING:<span class="hljs-comment">// 准备下载</span> observer.onPrepare(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DOWNLOADING:<span class="hljs-comment">// 下载中</span> observer.onProgress(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_PAUSED:<span class="hljs-comment">// 暂停</span> observer.onStop(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DOWNLOADED:<span class="hljs-comment">// 下载完毕</span> observer.onFinish(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_ERROR:<span class="hljs-comment">// 下载失败</span> observer.onError(bean); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> STATE_DELETE:<span class="hljs-comment">// 删除成功</span> observer.onDelete(bean); <span class="hljs-keyword">break</span>; } } } } <span class="hljs-javadoc">/** 当下载状态发送改变的时候调用 */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">notifyDownloadStateChanged</span>(DownLoadBean bean) { Message message = handler.obtainMessage(); message.obj = bean; handler.sendMessage(message); }</code>
这里我们拿到数据的同时需要跟数据库里面的进行比较,如果数据库里面有跟现在的数据id相同的就得把数据库的数据放入
当前的集合里面并且拿到文件路径去取文件的长度来显示。
注意在onDestroy方法里面注销监听,也就是销毁的时候注销监听
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> {</span> <span class="hljs-javadoc">/** 列表控件 */</span> <span class="hljs-keyword">public</span> ListView listview; <span class="hljs-javadoc">/** 列表数据bean */</span> <span class="hljs-keyword">public</span> ArrayList<DownLoadBean> list; <span class="hljs-keyword">public</span> DownAdapter adapter; <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); setContentView(R.layout.activity_main); list = <span class="hljs-keyword">new</span> ArrayList<DownLoadBean>(); Test(); listview = (ListView) findViewById(R.id.listview); adapter = <span class="hljs-keyword">new</span> DownAdapter(MainActivity.<span class="hljs-keyword">this</span>, list); listview.setAdapter(adapter); } <span class="hljs-comment">// 测试数据</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Test</span>() { DownLoadBean bean1 = <span class="hljs-keyword">new</span> DownLoadBean(); bean1.id = <span class="hljs-string">"3210158"</span>; bean1.appName = <span class="hljs-string">"剑与魔法"</span>; bean1.appSize = <span class="hljs-number">252821785</span>; bean1.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t0170f68197b3c8efe9.png"</span>; bean1.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160315/168f6b5f7e38b95f8d7dcce94076acc4/com.longtugame.jymf.qihoo_22.apk"</span>; DownLoadBean bean2 = <span class="hljs-keyword">new</span> DownLoadBean(); bean2.id = <span class="hljs-string">"2981222"</span>; bean2.appName = <span class="hljs-string">"花椒-高颜值的直播App"</span>; bean2.appSize = <span class="hljs-number">17699443</span>; bean2.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t01c52b0ee594a7f507.png"</span>; bean2.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160318/a043152dd8789131a12c5beeb7e42e34/com.huajiao_4071059.apk"</span>; DownLoadBean bean3 = <span class="hljs-keyword">new</span> DownLoadBean(); bean3.id = <span class="hljs-string">"21972"</span>; bean3.appName = <span class="hljs-string">"唯品会"</span>; bean3.appSize = <span class="hljs-number">33411097</span>; bean3.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t016c539aa97fdef5bf.png"</span>; bean3.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160310/5aae1072a87bf4cef0ccec0e17999d27/com.achievo.vipshop_436.apk"</span>; DownLoadBean bean4 = <span class="hljs-keyword">new</span> DownLoadBean(); bean4.id = <span class="hljs-string">"1625930"</span>; bean4.appName = <span class="hljs-string">"开心消消乐"</span>; bean4.appSize = <span class="hljs-number">67771094</span>; bean4.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t01fbaee14a2b65be0f.png"</span>; bean4.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160310/ca3b2c5ab347fc988dde0325e6f7c658/com.happyelements.AndroidAnimal_31.apk"</span>; DownLoadBean bean5 = <span class="hljs-keyword">new</span> DownLoadBean(); bean5.id = <span class="hljs-string">"8043"</span>; bean5.appName = <span class="hljs-string">"阿里旅行"</span>; bean5.appSize = <span class="hljs-number">33840292</span>; bean5.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t01c513232212e2d915.png"</span>; bean5.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160317/0a2c6811b5fc9bada8e7e082fb5a9324/com.taobao.trip_3001049.apk"</span>; DownLoadBean bean6 = <span class="hljs-keyword">new</span> DownLoadBean(); bean6.id = <span class="hljs-string">"65533"</span>; bean6.appName = <span class="hljs-string">"苏宁易购"</span>; bean6.appSize = <span class="hljs-number">27854306</span>; bean6.appIcon = <span class="hljs-string">"http://p1.qhimg.com/dr/160_160_/t01f9b42c0addddd698.png"</span>; bean6.url = <span class="hljs-string">"http://m.shouji.360tpcdn.com/160316/deab26b43b55089736817040f921c1e7/com.suning.mobile.ebuy_120.apk"</span>; list.add(bean1); list.add(bean2); list.add(bean3); list.add(bean4); list.add(bean5); list.add(bean6); ArrayList<DownLoadBean> list_lin = DataBaseUtil.getDownLoad(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < list_lin.size(); i++) { <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j < list.size(); j++) { <span class="hljs-keyword">if</span> (list_lin.get(i).id.equals(list.get(j).id)) { list.remove(j); File file = <span class="hljs-keyword">new</span> File(list_lin.get(i).getPath()); <span class="hljs-keyword">if</span> (file.exists()) { list_lin.get(i).currentSize = file.length(); } list.add(j, list_lin.get(i)); <span class="hljs-keyword">break</span>; } } } } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDestroy</span>() { DownLoadManager.getInstance().RemoveObserver(); <span class="hljs-keyword">super</span>.onDestroy(); } }</code>
这是adapter,显示时则需要根据状态来不一样的显示,然后注册下载监听(根据每个回调来进行不一样的显示,每个回调都会有个下载bean)、点击下载和点击删除。
<code class="hljs java has-numbering"> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DownAdapter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseAdapter</span> {</span> <span class="hljs-keyword">public</span> ArrayList<DownLoadBean> list; <span class="hljs-keyword">public</span> Context context; <span class="hljs-keyword">public</span> <span class="hljs-title">DownAdapter</span>(Context context, ArrayList<DownLoadBean> list) { <span class="hljs-keyword">this</span>.context = context; <span class="hljs-keyword">this</span>.list = list; } <span class="hljs-javadoc">/** * 换算文件的大小 */</span> <span class="hljs-keyword">public</span> String <span class="hljs-title">FormetFileSize</span>(<span class="hljs-keyword">long</span> fileSize) {<span class="hljs-comment">// 转换文件大小</span> <span class="hljs-keyword">if</span> (fileSize <= <span class="hljs-number">0</span>) { <span class="hljs-keyword">return</span> <span class="hljs-string">"0M"</span>; } DecimalFormat df = <span class="hljs-keyword">new</span> DecimalFormat(<span class="hljs-string">"#.00"</span>); String fileSizeString = <span class="hljs-string">""</span>; <span class="hljs-keyword">if</span> (fileSize < <span class="hljs-number">1024</span>) { fileSizeString = df.format((<span class="hljs-keyword">double</span>) fileSize) + <span class="hljs-string">"B"</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (fileSize < <span class="hljs-number">1048576</span>) { fileSizeString = df.format((<span class="hljs-keyword">double</span>) fileSize / <span class="hljs-number">1024</span>) + <span class="hljs-string">"K"</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (fileSize < <span class="hljs-number">1073741824</span>) { fileSizeString = df.format((<span class="hljs-keyword">double</span>) fileSize / <span class="hljs-number">1048576</span>) + <span class="hljs-string">"M"</span>; } <span class="hljs-keyword">else</span> { fileSizeString = df.format((<span class="hljs-keyword">double</span>) fileSize / <span class="hljs-number">1073741824</span>) + <span class="hljs-string">"G"</span>; } <span class="hljs-keyword">return</span> fileSizeString; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCount</span>() { <span class="hljs-keyword">return</span> list.size(); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> Object <span class="hljs-title">getItem</span>(<span class="hljs-keyword">int</span> position) { <span class="hljs-keyword">return</span> list.get(position); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">getItemId</span>(<span class="hljs-keyword">int</span> position) { <span class="hljs-keyword">return</span> position; } <span class="hljs-annotation">@SuppressLint</span>(<span class="hljs-string">"InflateParams"</span>) <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> View <span class="hljs-title">getView</span>(<span class="hljs-keyword">int</span> position, View convertView, ViewGroup parent) { <span class="hljs-keyword">final</span> ViewHolder viewHolder; <span class="hljs-keyword">final</span> DownLoadBean bean = list.get(position); <span class="hljs-keyword">if</span> (convertView == <span class="hljs-keyword">null</span>) { viewHolder = <span class="hljs-keyword">new</span> ViewHolder(); convertView = LayoutInflater.from(context).inflate( R.layout.item_down, <span class="hljs-keyword">null</span>); viewHolder.txt_name = (TextView) convertView .findViewById(R.id.txt_name); viewHolder.txt_state = (TextView) convertView .findViewById(R.id.txt_state); viewHolder.btn_delete = (Button) convertView .findViewById(R.id.btn_delete); viewHolder.txt_file_size = (TextView) convertView .findViewById(R.id.txt_file_size); viewHolder.seekbar = (SeekBar) convertView .findViewById(R.id.seekbar); convertView.setTag(viewHolder); } <span class="hljs-keyword">else</span> { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.txt_name.setText(bean.appName); viewHolder.txt_file_size.setText(FormetFileSize(bean.currentSize) + <span class="hljs-string">" / "</span> + FormetFileSize(bean.appSize)); <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_START) { viewHolder.txt_state.setText(<span class="hljs-string">"开始下载"</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_WAITING) { viewHolder.txt_state.setText(<span class="hljs-string">"排队等待中"</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_DOWNLOADING) { viewHolder.txt_state.setText(<span class="hljs-string">"下载中"</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_PAUSED) { viewHolder.txt_state.setText(<span class="hljs-string">"暂停中"</span>); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_DOWNLOADED) { viewHolder.txt_state.setText(<span class="hljs-string">"下载完成"</span>); viewHolder.btn_delete.setVisibility(View.GONE); } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (bean.downloadState == DownLoadManager.STATE_ERROR) { viewHolder.txt_state.setText(<span class="hljs-string">"下载失败,请重新下载"</span>); } <span class="hljs-keyword">else</span> { viewHolder.txt_state.setText(<span class="hljs-string">"点击下载"</span>); } viewHolder.seekbar.setProgress((<span class="hljs-keyword">int</span>) ((<span class="hljs-keyword">float</span>) bean.currentSize / (<span class="hljs-keyword">float</span>) bean.appSize * <span class="hljs-number">100</span>f)); viewHolder.seekbar.setMax(<span class="hljs-number">100</span>); DownLoadManager.getInstance().registerObserver(bean.id, <span class="hljs-keyword">new</span> DownLoadObserver() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStop</span>(DownLoadBean bean) { viewHolder.txt_state.setText(<span class="hljs-string">"暂停中"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>(DownLoadBean bean) { viewHolder.txt_state.setText(<span class="hljs-string">"开始下载"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onProgress</span>(DownLoadBean bean) { viewHolder.txt_file_size .setText(FormetFileSize(bean.currentSize) + <span class="hljs-string">" / "</span> + FormetFileSize(bean.appSize)); viewHolder.txt_state.setText(<span class="hljs-string">"下载中"</span>); viewHolder.seekbar .setProgress((<span class="hljs-keyword">int</span>) ((<span class="hljs-keyword">float</span>) bean.currentSize / (<span class="hljs-keyword">float</span>) bean.appSize * <span class="hljs-number">100</span>f)); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onPrepare</span>(DownLoadBean bean) { viewHolder.txt_state.setText(<span class="hljs-string">"排队等待中"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>(DownLoadBean bean) { viewHolder.txt_state.setText(<span class="hljs-string">"下载完成"</span>); viewHolder.btn_delete.setVisibility(View.GONE); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span>(DownLoadBean bean) { viewHolder.txt_state.setText(<span class="hljs-string">"下载失败,请重新下载"</span>); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDelete</span>(DownLoadBean bean) { <span class="hljs-comment">// 删除成功之后的接口</span> viewHolder.txt_state.setText(<span class="hljs-string">"点击下载"</span>); viewHolder.txt_file_size.setText(FormetFileSize(<span class="hljs-number">0</span>) + <span class="hljs-string">" / "</span> + FormetFileSize(bean.appSize)); viewHolder.seekbar.setProgress(<span class="hljs-number">0</span>); } }); convertView.setOnClickListener(<span class="hljs-keyword">new</span> OnClickListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) { <span class="hljs-comment">// 开启下载</span> DownLoadManager.getInstance().download(bean); } }); viewHolder.btn_delete.setOnClickListener(<span class="hljs-keyword">new</span> OnClickListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) { <span class="hljs-comment">// 删除当前任务</span> DownLoadManager.getInstance().DeleteDownTask(bean); } }); <span class="hljs-keyword">return</span> convertView; } <span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewHolder</span> {</span> <span class="hljs-keyword">private</span> TextView txt_name; <span class="hljs-keyword">private</span> Button btn_delete; <span class="hljs-keyword">private</span> TextView txt_state; <span class="hljs-keyword">private</span> TextView txt_file_size; <span class="hljs-keyword">private</span> SeekBar seekbar; } }</code>
demo里面和博客里面貌似忘记关闭流了,关闭流请在判断网络状态码里面自行加上,分别在while循环一开头的判断里面和下载完之后关闭流。请看代码:
<code class="hljs avrasm has-numbering"> // 暂停就回调,然后直接返回 if (bean<span class="hljs-preprocessor">.downloadState</span> == STATE_PAUSED) { bean<span class="hljs-preprocessor">.downloadState</span> = STATE_PAUSED<span class="hljs-comment">;</span> DataBaseUtil<span class="hljs-preprocessor">.UpdateDownLoadById</span>(bean)<span class="hljs-comment">;</span> notifyDownloadStateChanged(bean)<span class="hljs-comment">;</span> //关闭流 outputStream<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span> is<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span> return<span class="hljs-comment">;</span> } else if (bean<span class="hljs-preprocessor">.downloadState</span> == STATE_DELETE) {// 下载的时候删除直接回调界面,然后直接返回 bean<span class="hljs-preprocessor">.downloadState</span> = STATE_DELETE<span class="hljs-comment">;</span> notifyDownloadStateChanged(bean)<span class="hljs-comment">;</span> mTaskMap<span class="hljs-preprocessor">.remove</span>(bean<span class="hljs-preprocessor">.id</span>)<span class="hljs-comment">;</span> //关闭流 outputStream<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span> is<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span> return<span class="hljs-comment">;</span> } //下载完之后回调成功之后需要关闭流 if (bean<span class="hljs-preprocessor">.appSize</span> == bean<span class="hljs-preprocessor">.currentSize</span>) { bean<span class="hljs-preprocessor">.downloadState</span> = STATE_DOWNLOADED<span class="hljs-comment">;</span> DataBaseUtil<span class="hljs-preprocessor">.UpdateDownLoadById</span>(bean)<span class="hljs-comment">;</span> notifyDownloadStateChanged(bean)<span class="hljs-comment">;</span> } else { bean<span class="hljs-preprocessor">.downloadState</span> = STATE_ERROR<span class="hljs-comment">;</span> DataBaseUtil<span class="hljs-preprocessor">.UpdateDownLoadById</span>(bean)<span class="hljs-comment">;</span> notifyDownloadStateChanged(bean)<span class="hljs-comment">;</span> bean<span class="hljs-preprocessor">.currentSize</span> = <span class="hljs-number">0</span><span class="hljs-comment">;// 错误状态需要删除文件</span> file<span class="hljs-preprocessor">.delete</span>()<span class="hljs-comment">;</span> } //关闭流 outputStream<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span> is<span class="hljs-preprocessor">.close</span>()<span class="hljs-comment">;</span></code><ul class="pre-numbering"><li> </li></ul>