Android的斷點下載詳細分析一
在Android中斷點下載用的很多,看了黎活明老師的教程之後,對斷點下載也有一定的認識,然後跟大家分享。
首先,斷點下載他的功能描述:使用者可以從網路上下載任意的資源,使用斷點下載的好處就是:當使用者由於一些其他的原因退出了本應用,但是此時正在下載者一些檔案,當使用者再次點進本應用的時候,我們不應該讓使用者重新下載該檔案,而是從上次下載完成的那個地方開始繼續下載,這就是斷點下載的功能。
實現思路:從網路下載資源,需要使用到HTTP協議(如果是資源比較大的建議使用socket,比如上百M的),需要使用到多線程,Android4.x之後不允許在UI線程訪問網路,所以我們需要使用多線程,或者是非同步任務,volley等其他,然後因為需要當使用者退出應用再進入的時候讀取原來的下載進度,因此我們需要使用到SQLite技術,用於儲存每一條線程的下載進度,每當用於再次進入的時候可以從資料庫讀取資料然後傳到線程那裡,從他以前停止下載的位置開始下載。
下面是一些源碼分析:
這是MainActivity.java
public class MainActivity extends Activity {/* * 下載路徑text */ private EditText pathText;/* * 下載結果顯示 */ private TextView resultView;/* * 點擊下載button */ private Button downloadButton;/* * 點擊停止button */ private Button stopbutton;/* * 顯示進度progressBar */ private ProgressBar progressBar;/* * hanlder的作用是用於往建立Hander對象所在的線程所綁定的訊息佇列發送訊息 * 這裡是UI線程的Handler,改變progressBar,resultText */ private Handler handler = new UIHander(); private final class UIHander extends Handler{public void handleMessage(Message msg) {switch (msg.what) {case 1:int size = msg.getData().getInt("size");progressBar.setProgress(size);float num = (float)progressBar.getProgress() / (float)progressBar.getMax();int result = (int)(num * 100);resultView.setText(result+ "%");//progressBar達到最大值,下載完成if(progressBar.getProgress() == progressBar.getMax()){Toast.makeText(getApplicationContext(), R.string.success, 1).show();}break;case -1://下載失敗Toast.makeText(getApplicationContext(), R.string.error, 1).show();break;}} } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /* * 初始化各個UI */ pathText = (EditText) this.findViewById(R.id.path); resultView = (TextView) this.findViewById(R.id.resultView); downloadButton = (Button) this.findViewById(R.id.downloadbutton); stopbutton = (Button) this.findViewById(R.id.stopbutton); progressBar = (ProgressBar) this.findViewById(R.id.progressBar); /* * 設定點擊時間 */ ButtonClickListener listener = new ButtonClickListener(); downloadButton.setOnClickListener(listener); stopbutton.setOnClickListener(listener); } private final class ButtonClickListener implements View.OnClickListener{public void onClick(View v) {switch (v.getId()) {/* * 下載按鈕 */case R.id.downloadbutton:String path = pathText.getText().toString();if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File saveDir = Environment.getExternalStorageDirectory();//擷取儲存路徑download(path, saveDir);//開始下載}else{//記憶卡出錯Toast.makeText(getApplicationContext(), R.string.sdcarderror, 1).show();}downloadButton.setEnabled(false);//設定下載按鈕不可用stopbutton.setEnabled(true);//設定停止下載按鈕可用break;//停止下載case R.id.stopbutton:this.task.exit();//退出下載,即是去讓線程停止下載downloadButton.setEnabled(true);//下載按鈕可用stopbutton.setEnabled(false);//停止下載按鈕不可用break;}}private DownloadTask task;private void download(String path, File saveDir) {//運行在主線程task = new DownloadTask(path, saveDir);new Thread(task).start();}/* * UI控制項畫面的重繪(更新)是由主線程負責處理的,如果在子線程中更新UI控制項的值,更新後的值不會重繪到螢幕上 * 一定要在主線程裡更新UI控制項的值,這樣才能在螢幕上顯示出來,不能在子線程中更新UI控制項的值 */private final class DownloadTask implements Runnable{private String path;private File saveDir;private FileDownloader loader;public DownloadTask(String path, File saveDir) {this.path = path;this.saveDir = saveDir;}/** * 退出下載 */public void exit(){if(loader!=null) loader.exit();}public void run() {try {loader = new FileDownloader(getApplicationContext(), path, saveDir, 3);//開啟三條線程下載progressBar.setMax(loader.getFileSize());//設定進度條的最大刻度,為檔案的長度loader.download(new DownloadProgressListener() {public void onDownloadSize(int size) {Message msg = new Message();msg.what = 1;msg.getData().putInt("size", size);//把已經下載的長度傳給UI線程,在progressbar中顯示handler.sendMessage(msg);}});} catch (Exception e) {e.printStackTrace();handler.sendMessage(handler.obtainMessage(-1));}}} } }
源碼解析:這裡主要的是Handler的使用,他是在子線程中當下載進度發生變化之後通知UI線程去更新ProgressBar和ResultView的。而子DownloadTask線程中通過調用download方法,download中包含一個沒有下載完成之前不停止的迴圈,傳入DownloadProgressListener對象而可以監聽不斷的發現下載進度改變,之後發訊息。這樣一個輪迴就可以實現子線程不斷的發訊息給UI線程,UI線程更新群組件這樣的功能。這樣MainActivity就完美了。