-
完成下載任務(wù) 1.上一筆記已經(jīng)完成了下載線程的具體實(shí)現(xiàn),小結(jié): (1)這個(gè)例子是單線程的,所以數(shù)據(jù)庫中只有finished元素是有用的,其他的元素初始化以后一直都不會變。 即start=0,end=文件長度,url=文件地址 (2)第一次開始下載,start=finished=0,只有下載開始了才會mFinished += len來更新mFinished,然后會更新到數(shù)據(jù)庫中 mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinished); (3)接下來再點(diǎn)下載,start將會更新 start = mThreadInfo.getStart()+mThreadInfo.getFinished();//getStart()=0 mFinished也會被更新 mFinished += mThreadInfo.getFinished(); (4)最后一點(diǎn)比較重要!mFinished初始值=0,即使第二次以后點(diǎn)擊開始按鈕,進(jìn)來mFinished還是0,更新時(shí)是從數(shù)據(jù)庫中直接讀取的。 2.在下載任務(wù)類中開始這個(gè)線程 3.在DownloadService中獲得文件長度之后就啟動(dòng)下載任務(wù) 4.當(dāng)點(diǎn)擊停止按鈕時(shí),就把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; } 這樣后臺運(yùn)行的DownloadService就會停止 if (isPause){ mDao.updateThread(…, …, mFinished); return; }查看全部
-
下載任務(wù)類和下載操作 1.到這里,對數(shù)據(jù)庫的操作也完成了,可以讀取和更新ThreadInfo了。 2.接下來就要?jiǎng)?chuàng)建一個(gè)下載任務(wù)類,并在這里開辟一個(gè)線程來下載文件 public class DownloadThread extends Thread{ run()方法: (1)如果剛開始下載,就向數(shù)據(jù)庫中插入線程信息 if (!mDao.isExist(mThreadInfo.getUrl(), mThreadInfo.getId())){ mDao.insertThread(mThreadInfo); } (2)設(shè)置下載位置 int start = mThreadInfo.getStart()+mThreadInfo.getFinished(); conn.setRequestProperty("Range", "bytes=" + start + "-" + mThreadInfo.getEnd()); (3)設(shè)置文件寫入位置 raf = new RandomAccessFile(file, "rwd"); raf.seek(start); //從start位置開始寫 (4)開始下載 讀寫流操作,沒什么好說的 (5)把下載進(jìn)度通過廣播發(fā)給主線程 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)下載停止時(shí)保存當(dāng)前下載進(jìn)度 if (isPause){ mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mFinished); return; } (7)下載完成 mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId());查看全部
-
一、創(chuàng)建數(shù)據(jù)庫和訪問接口 1.通過上一筆記知道,在獲取到網(wǎng)絡(luò)文件的長度之后就要開始下載任務(wù)了。下載任務(wù)要讀取上次下載的信息,然后繼續(xù)下載,這就需要一個(gè)數(shù)據(jù)庫來保存ThreadInfo的信息,并由下載任務(wù)讀取和更新這個(gè)數(shù)據(jù)庫 2.創(chuàng)建一個(gè)DBHelper繼承自SQLiteOpenHelper,它的作用就是創(chuàng)建數(shù)據(jù)庫,并通過SQLiteDatabase db = mHelper.getWritableDatabase()來獲取一個(gè)SQLiteDatabase對象對數(shù)據(jù)庫進(jìn)行增刪查改的操作 代碼如圖 3.創(chuàng)建一個(gè)Interface,包含對數(shù)據(jù)庫進(jìn)行增刪查改的接口 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); 二、數(shù)據(jù)庫訪問接口實(shí)現(xiàn) 這一部分都是SQL語句的一些操作,唯一需要注意的就是SQL語句千萬不要有錯(cuò)字,漏字,否則這樣的bug非常難排查,因?yàn)镾QL語句沒有語法檢查。 代碼實(shí)現(xiàn)自己看一下代碼。 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知識點(diǎn)的筆記:http://idcbgp.cn/space/notelist/uid/1859625/cid/179/sort/1/coll/1/page/2查看全部
-
通過線程對網(wǎng)絡(luò)文件長度初始化 1.上一筆記說到DownloadService接收到intent后會執(zhí)行開始/停止下載的操作。 如果是Action對應(yīng)的是ACTION_START,會獲取MainActivity傳來的fileInfo intent.getSerializableExtra("fileInfo");//這也是為什么FileInfo要實(shí)現(xiàn)Serializable接口 2.接下來要做一個(gè)不主要但必要的操作:通過開辟一個(gè)線程來獲得網(wǎng)絡(luò)文件的長度 因?yàn)橐ㄟ^長度值來給本地文件設(shè)置長度,同時(shí)進(jìn)度條也要根據(jù)這個(gè)長度來更新進(jìn)度條。 3.開辟一個(gè)線程來獲取網(wǎng)絡(luò)文件的長度,并更新給主線程 代碼如圖,或自己看代碼。 注意: (1)響應(yīng)碼判斷 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK){ length = conn.getContentLength(); } (2)設(shè)置文件長度并回傳給主線程Handler mFileInfo.setLength(length); mHandler.obtainMessage(MSG_INIT, mFileInfo).sendToTarget(); (3)主線程handler實(shí)現(xiàn) public void handleMessage(Message msg) { switch (msg.what){ case MSG_INIT: FileInfo fileInfo = (FileInfo) msg.obj; 獲取到更新長度的fileInfo對象之后就啟動(dòng)下載任務(wù); break; } } 4.最后這個(gè)InitThread線程在這里開啟 if (ACTION_START == intent.getAction()){ FileInfo fileInfo = (FileInfo) intent.getSerializableExtra("fileInfo"); //啟動(dòng)初始化線程 new InitThread(fileInfo).start(); } 通過InitThread獲取到網(wǎng)絡(luò)文件長度后使用Handler回傳給主線程,然后開始下載任務(wù)。查看全部
-
一、UI和實(shí)體類 1.在MainActivity中要實(shí)現(xiàn)UI,這是主界面的載體,界面很簡單(略) 2.需要兩個(gè)實(shí)體類: (1)FileInfo類,用來保存網(wǎng)絡(luò)文件信息,它會由MainActivity傳遞給Service,由Service來執(zhí)行下載任務(wù) public class FileInfo implements Serializable{ private int id; private String url; private String fileName; private int length; private int finished; (2)ThreadInfo類,用來保存下載線程信息,它會被保存到數(shù)據(jù)庫中,當(dāng)下載操作開始時(shí)會從數(shù)據(jù)庫中讀取并繼續(xù)下載任務(wù);當(dāng)下載操作暫停時(shí),又會通過ThreadInfo將下載進(jìn)度保存到數(shù)據(jù)庫中,方便下次讀取 public class ThreadInfo { private int id; private String url; private int start; private int end; private int finished; 3.對于兩個(gè)實(shí)體類,一定要實(shí)現(xiàn)其get()/set()方法;并注意為了便于測試,一定要實(shí)現(xiàn)他們的toString()方法(見代碼) 二、向Service傳參 新建一個(gè)DownloadService類繼承Service類,來接收MainActivity傳來的FileInfo對象,并對這個(gè)FileInfo繼續(xù)處理 public class DownloadService extends Service { 1.因?yàn)樵贛ainActivity有兩個(gè)操作,即開始下載和停止下載,所以要定義兩個(gè)Action public static final String ACTION_START = "ACTION_START"; public static final String ACTION_STOP = "ACTION_STOP"; 2.當(dāng)點(diǎn)擊相應(yīng)按鈕時(shí),會調(diào)用startService(intent)讓DownloadService開始/停止下載,然后在DownloadService的onStartCommand()接收到intent之后,會匹配其action,最后開始/停止下載操作。(如圖)查看全部
-
案例分析 1.框架圖詳細(xì)分析: (1)Activity中有一個(gè)BroadcastReceiver Activity通過傳遞下載文件地址url給service,service負(fù)責(zé)下載文件 (2)service和activity同屬于主線程,所以它會啟動(dòng)一個(gè)子線程來執(zhí)行下載 (3)子線程Thread會通過網(wǎng)絡(luò)操作從網(wǎng)絡(luò)地址下載文件到本地,同時(shí)將下載的進(jìn)度保存到數(shù)據(jù)庫中 (4)子線程還會通過發(fā)送broadcast給activity,讓后者更新進(jìn)度條 2.網(wǎng)絡(luò)下載的關(guān)鍵點(diǎn) (1)獲得網(wǎng)絡(luò)文件的長度 (2)本地創(chuàng)建一個(gè)文件,和網(wǎng)絡(luò)文件的大小一致 (3)從數(shù)據(jù)庫中獲取上次下載的進(jìn)度,以便續(xù)傳 (4)繼續(xù)下載,并將進(jìn)度保存到數(shù)據(jù)庫中 (5)將下載進(jìn)度回傳給activity (6)下載完成后刪除下載信息查看全部
-
seek設(shè)置文件寫入位置查看全部
-
如果不使用service ,當(dāng)用戶退出當(dāng)前界面時(shí),那么當(dāng)前界面創(chuàng)建的線程就無法進(jìn)行管理查看全部
-
學(xué)習(xí)內(nèi)容:<br><br> 基本UI定義<br><br> 數(shù)據(jù)庫的操作:把下載的進(jìn)度保存到數(shù)據(jù)庫里,實(shí)現(xiàn)斷點(diǎn)續(xù)傳<br> Serviced的啟動(dòng)<br>:(service也是屬于主線程) Activity 給 Service傳遞參數(shù) (文件名,下載URL)<br> 使用廣播回傳數(shù)據(jù)到activity(下載進(jìn)度)<br> 線程和handler<br> 網(wǎng)絡(luò)操作 ========================================= 網(wǎng)絡(luò)下載關(guān)鍵點(diǎn): 獲得網(wǎng)絡(luò)文件的長度 在本地創(chuàng)建一個(gè)文件,設(shè)置其長度 從數(shù)據(jù)庫中獲得上次下載的進(jìn)度 從上次下載的位置下載數(shù)據(jù),同時(shí)保存數(shù)據(jù)到數(shù)據(jù)庫 將下載進(jìn)度回傳Activity 下載完成后刪除下載信息查看全部
-
為什么沒有取消按鈕呀?查看全部
-
我也是xray查看全部
-
RandomAccessFile的seek()方法:查看全部
-
原理圖:查看全部
-
講的還是不錯(cuò)的,但是需要注意代碼風(fēng)格。 駝峰和下劃線不要混用啊查看全部
-
案例分析查看全部
舉報(bào)
0/150
提交
取消