-
完成下載任務 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.xianlaiwan.cn/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
提交
取消