Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的斷點下載詳細分析一

Android的斷點下載詳細分析一

編輯:關於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就完美了。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved