-
完成下载任务 1.上一笔记已经完成了下载线程的具体实现,小结: (1)这个例子是单线程的,所以数据库中只有finished元素是有用的,其他的元素初始化以后一直都不会变。 即start=0,end=文件长度,url=文件地址 (2)第一次开始下载,start=finished=0,只有下载开始了才会mFinished += len来更新mFinished,然后会更新到数据库中 mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinished); (3)接下来再点下载,start将会更新 start = mThreadInfo.getStart()+mThreadInfo.getFinished();//getStart()=0 mFinished也会被更新 mFinished += mThreadInfo.getFinished(); (4)最后一点比较重要!mFinished初始值=0,即使第二次以后点击开始按钮,进来mFinished还是0,更新时是从数据库中直接读取的。 2.在下载任务类中开始这个线程 3.在DownloadService中获得文件长度之后就启动下载任务 4.当点击停止按钮时,就把mTask.isPause置为true if (ACTION_STOP == intent.getAction()){ FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo"); Log.i(LOG_TAG, "Stop: "+fileInfo.toString()); if (mTask != null){ mTask.isPause = true; } 这样后台运行的DownloadService就会停止 if (isPause){ mDao.updateThread(…, …, mFinished); return; }查看全部
-
下载任务类和下载操作 1.到这里,对数据库的操作也完成了,可以读取和更新ThreadInfo了。 2.接下来就要创建一个下载任务类,并在这里开辟一个线程来下载文件 public class DownloadThread extends Thread{ run()方法: (1)如果刚开始下载,就向数据库中插入线程信息 if (!mDao.isExist(mThreadInfo.getUrl(), mThreadInfo.getId())){ mDao.insertThread(mThreadInfo); } (2)设置下载位置 int start = mThreadInfo.getStart()+mThreadInfo.getFinished(); conn.setRequestProperty("Range", "bytes=" + start + "-" + mThreadInfo.getEnd()); (3)设置文件写入位置 raf = new RandomAccessFile(file, "rwd"); raf.seek(start); //从start位置开始写 (4)开始下载 读写流操作,没什么好说的 (5)把下载进度通过广播发给主线程 Intent intent = new Intent(DownloadService.ACTION_UPDATE); mFinished += mThreadInfo.getFinished(); while((len = is.read(buffer)) != -1){ mFinished += len; intent.putExtra("finished", mFinished * 100 / mFileInfo.getLength()); mContext.sendBroadcast(intent); } (6)下载停止时保存当前下载进度 if (isPause){ mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinished); return; } (7)下载完成 mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId());查看全部
-
一、创建数据库和访问接口 1.通过上一笔记知道,在获取到网络文件的长度之后就要开始下载任务了。下载任务要读取上次下载的信息,然后继续下载,这就需要一个数据库来保存ThreadInfo的信息,并由下载任务读取和更新这个数据库 2.创建一个DBHelper继承自SQLiteOpenHelper,它的作用就是创建数据库,并通过SQLiteDatabase db = mHelper.getWritableDatabase()来获取一个SQLiteDatabase对象对数据库进行增删查改的操作 代码如图 3.创建一个Interface,包含对数据库进行增删查改的接口 void insertThread(ThreadInfo threadInfo); void deleteThread(String url, int thread_id); void updateThread(String url, int thread_id, int finished); //线程信息是否存在 List<ThreadInfo> getThread(String url); boolean isExist(String url, int thread_id); 二、数据库访问接口实现 这一部分都是SQL语句的一些操作,唯一需要注意的就是SQL语句千万不要有错字,漏字,否则这样的bug非常难排查,因为SQL语句没有语法检查。 代码实现自己看一下代码。 public void updateThread(String url, int thread_id, int finished) { SQLiteDatabase db = mHelper.getWritableDatabase(); db.execSQL("update thread_info set finished = ? where url = ? and thread_id = ?", new Object[]{finished, url, thread_id}); db.close(); } SQLite知识点的笔记:http://www.imooc.com/space/notelist/uid/1859625/cid/179/sort/1/coll/1/page/2查看全部
-
通过线程对网络文件长度初始化 1.上一笔记说到DownloadService接收到intent后会执行开始/停止下载的操作。 如果是Action对应的是ACTION_START,会获取MainActivity传来的fileInfo intent.getSerializableExtra("fileInfo");//这也是为什么FileInfo要实现Serializable接口 2.接下来要做一个不主要但必要的操作:通过开辟一个线程来获得网络文件的长度 因为要通过长度值来给本地文件设置长度,同时进度条也要根据这个长度来更新进度条。 3.开辟一个线程来获取网络文件的长度,并更新给主线程 代码如图,或自己看代码。 注意: (1)响应码判断 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK){ length = conn.getContentLength(); } (2)设置文件长度并回传给主线程Handler mFileInfo.setLength(length); mHandler.obtainMessage(MSG_INIT, mFileInfo).sendToTarget(); (3)主线程handler实现 public void handleMessage(Message msg) { switch (msg.what){ case MSG_INIT: FileInfo fileInfo = (FileInfo) msg.obj; 获取到更新长度的fileInfo对象之后就启动下载任务; break; } } 4.最后这个InitThread线程在这里开启 if (ACTION_START == intent.getAction()){ FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo"); //启动初始化线程 new InitThread(fileInfo).start(); } 通过InitThread获取到网络文件长度后使用Handler回传给主线程,然后开始下载任务。查看全部
-
一、UI和实体类 1.在MainActivity中要实现UI,这是主界面的载体,界面很简单(略) 2.需要两个实体类: (1)FileInfo类,用来保存网络文件信息,它会由MainActivity传递给Service,由Service来执行下载任务 public class FileInfo implements Serializable{ private int id; private String url; private String fileName; private int length; private int finished; (2)ThreadInfo类,用来保存下载线程信息,它会被保存到数据库中,当下载操作开始时会从数据库中读取并继续下载任务;当下载操作暂停时,又会通过ThreadInfo将下载进度保存到数据库中,方便下次读取 public class ThreadInfo { private int id; private String url; private int start; private int end; private int finished; 3.对于两个实体类,一定要实现其get()/set()方法;并注意为了便于测试,一定要实现他们的toString()方法(见代码) 二、向Service传参 新建一个DownloadService类继承Service类,来接收MainActivity传来的FileInfo对象,并对这个FileInfo继续处理 public class DownloadService extends Service { 1.因为在MainActivity有两个操作,即开始下载和停止下载,所以要定义两个Action public static final String ACTION_START = "ACTION_START"; public static final String ACTION_STOP = "ACTION_STOP"; 2.当点击相应按钮时,会调用startService(intent)让DownloadService开始/停止下载,然后在DownloadService的onStartCommand()接收到intent之后,会匹配其action,最后开始/停止下载操作。(如图)查看全部
-
案例分析 1.框架图详细分析: (1)Activity中有一个BroadcastReceiver Activity通过传递下载文件地址url给service,service负责下载文件 (2)service和activity同属于主线程,所以它会启动一个子线程来执行下载 (3)子线程Thread会通过网络操作从网络地址下载文件到本地,同时将下载的进度保存到数据库中 (4)子线程还会通过发送broadcast给activity,让后者更新进度条 2.网络下载的关键点 (1)获得网络文件的长度 (2)本地创建一个文件,和网络文件的大小一致 (3)从数据库中获取上次下载的进度,以便续传 (4)继续下载,并将进度保存到数据库中 (5)将下载进度回传给activity (6)下载完成后删除下载信息查看全部
-
seek设置文件写入位置查看全部
-
如果不使用service ,当用户退出当前界面时,那么当前界面创建的线程就无法进行管理查看全部
-
学习内容:<br><br> 基本UI定义<br><br> 数据库的操作:把下载的进度保存到数据库里,实现断点续传<br> Serviced的启动<br>:(service也是属于主线程) Activity 给 Service传递参数 (文件名,下载URL)<br> 使用广播回传数据到activity(下载进度)<br> 线程和handler<br> 网络操作 ========================================= 网络下载关键点: 获得网络文件的长度 在本地创建一个文件,设置其长度 从数据库中获得上次下载的进度 从上次下载的位置下载数据,同时保存数据到数据库 将下载进度回传Activity 下载完成后删除下载信息查看全部
-
为什么没有取消按钮呀?查看全部
-
我也是xray查看全部
-
RandomAccessFile的seek()方法:查看全部
-
原理图:查看全部
-
讲的还是不错的,但是需要注意代码风格。 驼峰和下划线不要混用啊查看全部
-
案例分析查看全部
举报
0/150
提交
取消