Android 斷點續傳原理以及實現_Android

來源:互聯網
上載者:User

Android 斷點續傳原理以及實現

0.  前言

在Android開發中,斷點續傳聽起來挺容易,在下載一個檔案時點擊暫停任務暫停,點擊開始會繼續下載檔案。但是真正實現起來知識點還是蠻多的,因此今天有時間實現了一下,並進行記錄。

1.  斷點續傳原理

在本地下載過程中要使用資料庫即時儲存到底儲存到檔案的哪個位置了,這樣點擊開始繼續傳遞時,才能通過HTTP的GET請求中的setRequestProperty()方法可以告訴伺服器,資料從哪裡開始,到哪裡結束。同時在本地的檔案寫入時,RandomAccessFile的seek()方法也支援在檔案中的任意位置進行寫入操作。同時通過廣播將子線程的進度告訴Activity的ProcessBar。

2.  Activity的按鈕響應

當點擊開始按鈕時,將url寫在了FileInfo類的對象info中並通過Intent從Activity傳遞到了Service中。這裡使用setAction()來區分是開始按鈕還是暫停按鈕。

public class FileInfo implements Serializable{   private String url; //URL   private int length; //長度或結束位置   private int start; //開始位置   private int now;//當前進度 //構造方法,set/get略 } //開始按鈕邏輯,停止邏輯大致相同 strat.setOnClickListener(new View.OnClickListener() {    @Override    public void onClick(View view) {     Intent intent = new Intent(MainActivity.this,DownLoadService.class);     intent.setAction(DownLoadService.ACTION_START);     intent.putExtra("fileUrl",info);     startService(intent);   } }); 

3.  在Service中的子線程中擷取檔案大小

在Service中的onStartCommand()中,將FileInfo對象從Intent中取出,如果是開始命令,則開啟一個線程,根據該url去獲得要下載檔案的大小,將該大小寫入對象並通過Handler傳回Service,同時在本地建立一個相同大小的本地檔案。暫停命令最後會講到。

public void run() {       HttpURLConnection urlConnection = null;       RandomAccessFile randomFile = null;       try {         URL url = new URL(fileInfo.getUrl());         urlConnection = (HttpURLConnection) url.openConnection();         urlConnection.setConnectTimeout(3000);         urlConnection.setRequestMethod("GET");         int length = -1;         if (urlConnection.getResponseCode() == HttpStatus.SC_OK) {           //獲得檔案長度           length = urlConnection.getContentLength();         }         if (length <= 0) {           return;         }         //建立相同大小的本地檔案         File dir = new File(DOWNLOAD_PATH);         if (!dir.exists()) {           dir.mkdir();         }         File file = new File(dir, FILE_NAME);         randomFile = new RandomAccessFile(file, "rwd");         randomFile.setLength(length);         //長度給fileInfo對象         fileInfo.setLength(length);         //通過Handler將對象傳遞給Service         mHandle.obtainMessage(0, fileInfo).sendToTarget();       } catch (Exception e) {         e.printStackTrace();       } finally { //流的回收邏輯略       }     }   } 

4.  資料庫操作封裝

在Service的handleMessage()方法中拿到有length屬性的FileInfo對象,並使用自訂的DownLoadUtil類進行具體的檔案下載邏輯。這裡傳入上下文,因為資料庫處理操作需要用到。

downLoadUtil = new DownLoadUtil(DownLoadService.this,info);downLoadUtil.download();

這裡有一個資料庫操作的介面ThreadDAO,內部有增刪改查等邏輯,用於記錄下載任務的資訊。自訂一個ThreadDAOImpl類將這裡的邏輯實現,內部資料庫建立關於繼承SQLiteOpenHelper的自訂類的邏輯就不貼了,比較簡單,該類會在ThreadDAOImpl類的構造方法中建立執行個體。完成底層資料庫操作的封裝。

public interface ThreadDAO {   //插入一條資料   public void insert(FileInfo info);   //根據URL刪除一條資料   public void delete(String url);   //根據URL更新一條進度   public void update(String url,int finished);   //根據URL找到一條資料   public List<FileInfo> get(String url);   //是否存在   public boolean isExits(String url); } 

5.  具體的檔案下載邏輯

public class DownLoadUtil {   //構造方法略   public void download(){     List<FileInfo> lists = threadDAO.get(fileInfo.getUrl());     FileInfo info = null;     if(lists.size() == 0){       //第一次下載,建立子線程下載       new MyThread(fileInfo).start();     }else{       //中間開始的       info = lists.get(0);       new MyThread(info).start();     }   }    class MyThread extends Thread{     private FileInfo info = null;     public MyThread(FileInfo threadInfo) {       this.info = threadInfo;     }     @Override     public void run() {       //向資料庫添加線程資訊       if(!threadDAO.isExits(info.getUrl())){         threadDAO.insert(info);       }       HttpURLConnection urlConnection = null;       RandomAccessFile randomFile =null;       InputStream inputStream = null;       try {         URL url = new URL(info.getUrl());         urlConnection = (HttpURLConnection) url.openConnection();         urlConnection.setConnectTimeout(3000);         urlConnection.setRequestMethod("GET");         //設定下載位置         int start = info.getStart() + info.getNow();         urlConnection.setRequestProperty("Range","bytes=" + start + "-" + info.getLength());          //設定檔案寫入位置         File file = new File(DOWNLOAD_PATH,FILE_NAME);         randomFile = new RandomAccessFile(file, "rwd");         randomFile.seek(start);          //向Activity發廣播         Intent intent = new Intent(ACTION_UPDATE);         finished += info.getNow();          if (urlConnection.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) {           //獲得檔案流           inputStream = urlConnection.getInputStream();           byte[] buffer = new byte[512];           int len = -1;           long time = System.currentTimeMillis();           while ((len = inputStream.read(buffer))!= -1){             //寫入檔案             randomFile.write(buffer,0,len);             //把進度發送給Activity             finished += len;             //看時間間隔,時間間隔大於500ms再發             if(System.currentTimeMillis() - time >500){               time = System.currentTimeMillis();               intent.putExtra("now",finished *100 /fileInfo.getLength());               context.sendBroadcast(intent);             }             //判斷是否是暫停狀態             if(isPause){               threadDAO.update(info.getUrl(),finished);               return; //結束迴圈             }           }           //刪除線程資訊           threadDAO.delete(info.getUrl());         }       }catch (Exception e){         e.printStackTrace();       }finally {//回收工作略       }     }   } } 

上面也講到使用自訂的DownLoadUtil類進行具體的檔案下載邏輯,這也是最關鍵的部分了,在該類的構造方法中進行ThreadDAOImpl執行個體的建立。並在download()中通過資料庫查詢的操作,判斷是否是第一次開始下載任務,如果是,則開啟一個子線程MyThread進行下載任務,否則將進度資訊從資料庫中取出,並將該資訊傳遞給MyThread。

在MyThread中,通過info.getStart() + info.getNow()設定開始下載的位置,如果是第一次下載兩個數將都是0,如果是暫停後再下載,則info.getNow()會取出非0值,該值來自資料庫儲存。使用setRequestProperty告知伺服器從哪裡開始傳遞資料,傳遞到哪裡結束,本地使用RandomAccessFile的seek()方法進行資料的本機存放區。使用廣播將進度的百分比傳遞給Activity,Activity再改變ProcessBar進行UI調整。

這裡很關鍵的一點是在使用者點擊暫停後會在Service中調用downLoadUtil.isPause = true,因此上面while迴圈會結束,停止下載並通過資料庫的update()儲存進度值。從而在續傳時取出該值,重新對伺服器發起檔案起始點的下載工作要求,同時也在本地檔案的相應位置繼續寫入操作。

6.  效果如下所示


感謝閱讀,希望能協助到大家,謝謝大家對本站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.