欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android 斷點續(xù)傳原理以及實現(xiàn)

 更新時間:2016年12月20日 10:07:39   投稿:lqh  
這篇文章主要介紹了Android 斷點續(xù)傳原理以及實現(xiàn)的相關資料,這里對斷點續(xù)傳原理進行了詳細介紹,需要的朋友可以參考下

Android 斷點續(xù)傳原理以及實現(xiàn)

0.  前言

在Android開發(fā)中,斷點續(xù)傳聽起來挺容易,在下載一個文件時點擊暫停任務暫停,點擊開始會繼續(xù)下載文件。但是真正實現(xiàn)起來知識點還是蠻多的,因此今天有時間實現(xiàn)了一下,并進行記錄。

1.  斷點續(xù)傳原理

在本地下載過程中要使用數(shù)據(jù)庫實時存儲到底存儲到文件的哪個位置了,這樣點擊開始繼續(xù)傳遞時,才能通過HTTP的GET請求中的setRequestProperty()方法可以告訴服務器,數(shù)據(jù)從哪里開始,到哪里結束。同時在本地的文件寫入時,RandomAccessFile的seek()方法也支持在文件中的任意位置進行寫入操作。同時通過廣播將子線程的進度告訴Activity的ProcessBar。

2.  Activity的按鈕響應

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

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中取出,如果是開始命令,則開啟一個線程,根據(jù)該url去獲得要下載文件的大小,將該大小寫入對象并通過Handler傳回Service,同時在本地創(chuàng)建一個相同大小的本地文件。暫停命令最后會講到。

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; 
        } 
        //創(chuàng)建相同大小的本地文件 
        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.  數(shù)據(jù)庫操作封裝

在Service的handleMessage()方法中拿到有l(wèi)ength屬性的FileInfo對象,并使用自定義的DownLoadUtil類進行具體的文件下載邏輯。這里傳入上下文,因為數(shù)據(jù)庫處理操作需要用到。

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

downLoadUtil.download();

這里有一個數(shù)據(jù)庫操作的接口ThreadDAO,內(nèi)部有增刪改查等邏輯,用于記錄下載任務的信息。自定義一個ThreadDAOImpl類將這里的邏輯實現(xiàn),內(nèi)部數(shù)據(jù)庫創(chuàng)建關于繼承SQLiteOpenHelper的自定義類的邏輯就不貼了,比較簡單,該類會在ThreadDAOImpl類的構造方法中創(chuàng)建實例。完成底層數(shù)據(jù)庫操作的封裝。

public interface ThreadDAO { 
  //插入一條數(shù)據(jù) 
  public void insert(FileInfo info); 
  //根據(jù)URL刪除一條數(shù)據(jù) 
  public void delete(String url); 
  //根據(jù)URL更新一條進度 
  public void update(String url,int finished); 
  //根據(jù)URL找到一條數(shù)據(jù) 
  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){ 
      //第一次下載,創(chuàng)建子線程下載 
      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() { 
      //向數(shù)據(jù)庫添加線程信息 
      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發(fā)廣播 
        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); 
            //把進度發(fā)送給Activity 
            finished += len; 
            //看時間間隔,時間間隔大于500ms再發(fā) 
            if(System.currentTimeMillis() - time >500){ 
              time = System.currentTimeMillis(); 
              intent.putExtra("now",finished *100 /fileInfo.getLength()); 
              context.sendBroadcast(intent); 
            } 
            //判斷是否是暫停狀態(tài) 
            if(isPause){ 
              threadDAO.update(info.getUrl(),finished); 
              return; //結束循環(huán) 
            } 
          } 
          //刪除線程信息 
          threadDAO.delete(info.getUrl()); 
        } 
      }catch (Exception e){ 
        e.printStackTrace(); 
      }finally {//回收工作略 
      } 
    } 
  } 
} 

上面也講到使用自定義的DownLoadUtil類進行具體的文件下載邏輯,這也是最關鍵的部分了,在該類的構造方法中進行ThreadDAOImpl實例的創(chuàng)建。并在download()中通過數(shù)據(jù)庫查詢的操作,判斷是否是第一次開始下載任務,如果是,則開啟一個子線程MyThread進行下載任務,否則將進度信息從數(shù)據(jù)庫中取出,并將該信息傳遞給MyThread。

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

這里很關鍵的一點是在用戶點擊暫停后會在Service中調用downLoadUtil.isPause = true,因此上面while循環(huán)會結束,停止下載并通過數(shù)據(jù)庫的update()保存進度值。從而在續(xù)傳時取出該值,重新對服務器發(fā)起文件起始點的下載任務請求,同時也在本地文件的相應位置繼續(xù)寫入操作。

6.  效果如下所示


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

相關文章

最新評論