標籤:返回 存在 定義 detail for迴圈 lan XML res net
progressBar說明
在某些操作的進度中的可視指標,為使用者呈現操作的進度,還它有一個次要的進度條,用來顯示中間進度,如在流媒體播放的緩衝區的進度。
一個進度條也可不確定其進度。在不確定模式下,進度條顯示迴圈動畫。這樣的模式經常使用於應用程式使用任務的長度是未知的。
XML重要屬性
android:progressBarStyle:預設進度條樣式
android:progressBarStyleHorizontal:水平樣式
progressBar重要方法
getMax():返回這個進度條的範圍的上限
getProgress():返回進度
getSecondaryProgress():返回次要進度
incrementProgressBy(int diff):指定添加的進度
isIndeterminate():指示進度條是否在不確定模式下
setIndeterminate(boolean indeterminate):設定不確定模式下
setVisibility(int v):設定該進度條是否可視
progressBar重要事件
onSizeChanged(int w, int h, int oldw, int oldh):當進度值改變時引發此事件
項目實現步驟分析
1.給進度調設定最大值
2.不管哪一個線程下載都要記錄進度條當前位置,並設定值
3.給textview設定顯示當前下載值
4.建立暫時檔案把曾經下載好的位置記錄起來
5.當線程下載完後刪除暫時儲存進度條位置的檔案
主要代碼:加入許可權
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
布局檔案
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android_download" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.android_download.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
StreamTools工具
android線程下載的工具一樣http://blog.csdn.net/zhaoyazhi2129/article/details/27189465
Activity主要代碼
package com.example.android_download;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.text.TextUtils;import android.view.View;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;import com.example.util.StreamTools;public class MainActivity extends Activity {private int threadNum = 3;// 線程開啟的數量private int threadRunning = 3;// 正在執行的線程private TextView tv_pb;private EditText et_url;private ProgressBar pb_download;private int currentPb;//當前值@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findView();File sdDir = Environment.getExternalStorageDirectory();File pdFile = new File(sdDir, "pb.txt");InputStream is = null;try {// 推斷檔案是否存在if (pdFile.exists()) {is = new FileInputStream(pdFile);}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}if (is != null) {String value = StreamTools.streamToStr(is);//拆分String arr[] = value.split(";");pb_download.setMax(Integer.valueOf(arr[0]));// 最大值currentPb = Integer.valueOf(arr[1]);// 當前值pb_download.setProgress(currentPb);tv_pb.setText("當前的進度是:"+arr[2]);}}/** * */public void findView() {tv_pb = (TextView) findViewById(R.id.tv_pb);et_url = (EditText) findViewById(R.id.et_url);pb_download = (ProgressBar) findViewById(R.id.pb_download);}// 下載檔案(得到server端的檔案大小 )public void downLoadFile(View v) {// 擷取下載路徑final String spec = et_url.getText().toString();if (TextUtils.isEmpty(spec)) {Toast.makeText(this, "不可為空", 0).show();} else {new Thread() {@Overridepublic void run() {// 訪問網路地址try {// 依據下載的地址構建url對象URL url = new URL(spec);// 通過URL對象的openConnection()方法開啟串連,返回一個連線物件HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();// 佈建要求頭httpURLConnection.setRequestMethod("GET");httpURLConnection.setConnectTimeout(5000);httpURLConnection.setReadTimeout(5000);// 推斷是否響應成功if (httpURLConnection.getResponseCode() == 200) {/** * 第一步:得到server下載檔案的大小,然後在本地設定一個暫時檔案和server端檔案大小一致 */// 擷取檔案長度int fileLength = httpURLConnection.getContentLength();//給進度條設定最大值pb_download.setMax(fileLength);//推斷SD卡是否可用if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){// 外部存放裝置的路徑File sdFile = Environment.getExternalStorageDirectory();//擷取檔案名稱String fileName = spec.substring(spec.lastIndexOf("/")+1);// 隨機訪問檔案的讀取與寫入RandomAccessFile(file, mode)RandomAccessFile accessFile = new RandomAccessFile(new File(sdFile, fileName), "rwd");// 設定暫時檔案與server檔案大小一致accessFile.setLength(fileLength);// 關閉暫時檔案accessFile.close();/** * 第二步:計算出每一個線程下載的大小(開始位置,結束位置) */// 計算出每一個線程下載的大小int threadSize = fileLength / threadNum;// for迴圈,計算出每一個線程的開始和結束位置for (int threadId = 1; threadId <= 3; threadId++) {int startIndex = (threadId - 1) * threadSize;// 開始位置int endIndex = threadId * threadSize - 1;// 結束位置if (threadId == threadNum) {// 最後一個 線程endIndex = fileLength - 1;}System.out.println("當前線程--" + threadId+ "-----開始位置" + startIndex + "----結束位置"+ endIndex + "-----線程大小" + threadSize);/** * 第三步:每建立好一次就要開啟線程下載 */new DownLoadThread(threadId, startIndex,endIndex, spec,fileName).start();}}else {runOnUiThread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "SD卡不存在", 1).show();}});}} else {runOnUiThread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "server端返回錯誤", 1).show();}});}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}.start();}}/** * 每建立好一次就要開啟線程下載 * * @author zhaoyazhi * */class DownLoadThread extends Thread {// 成員變數private int threadId;private int startIndex;private int endIndex;private String path;private String fileName;File sdFile = Environment.getExternalStorageDirectory();/** * * @param threadId * 線程的序號 * @param startIndex * 線程下載開始位置 * @param endIndex * 線程下載結束位置 * @param path * 線程下載儲存檔案的路徑 */public DownLoadThread(int threadId, int startIndex, int endIndex,String path,String fileName) {super();this.threadId = threadId;this.startIndex = startIndex;this.endIndex = endIndex;this.path = path;this.fileName = fileName;}@Overridepublic void run() {// 能夠通過每一個線程去下載檔案try {/** * 第四步:從本地檔案上讀取已經下載檔案的開始位置 */File recordFile = new File(sdFile, threadId + ".txt");if (recordFile.exists()) {// 讀取檔案InputStream is = new FileInputStream(recordFile);// 利用工具類轉換String value = StreamTools.streamToStr(is);// 擷取記錄的位置int recordIndex = Integer.parseInt(value);// 把記錄的位置付給開始位置startIndex = recordIndex;}// 通過path物件建構URL 對象URL url = new URL(path);// 通過URL對象openConnectionHttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();// 佈建要求頭httpURLConnection.setRequestMethod("GET");httpURLConnection.setConnectTimeout(5000);// 設定下載檔案的開始位置和結束位置httpURLConnection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex);// 擷取狀態代碼int code = httpURLConnection.getResponseCode();// System.out.println(code);// 推斷是否成功 僅僅要設定"Range"頭,返回的狀態代碼就是206if (code == 206) {// 擷取每一個線程返回的流對象InputStream is = httpURLConnection.getInputStream();// 建立隨機訪問的對象RandomAccessFile accessFile = new RandomAccessFile(new File(sdFile, fileName), "rwd");// 指定開始位置accessFile.seek(startIndex);// 定義讀取的長度int len = 0;// 定義緩衝區byte buffer[] = new byte[1024*1024];int total = 0;// 迴圈讀取while ((len = is.read(buffer)) != -1) {System.out.println("當前線程--" + threadId+ "-----當前下載的位置是" + (startIndex + total));// 儲存每一個線程的下載位置RandomAccessFile threadFile = new RandomAccessFile(new File(sdFile, threadId + ".txt"), "rwd");// 記錄每次下載位置threadFile.writeBytes((startIndex + total) + "");threadFile.close();accessFile.write(buffer, 0, len);total += len;// 已經下載大小/** * 當程式有多個線程訪問一個變數。能夠用synchronized解決 */synchronized (MainActivity.this) {//進度條當前進度currentPb += len;pb_download.setProgress(currentPb);final String percent= currentPb*100l/pb_download.getMax()+"%";runOnUiThread(new Runnable() {@Overridepublic void run() {//計算百分比操作tv_pb.setText("當前的進度是:"+percent);}});//建立儲存當前 進度和百分比RandomAccessFile pbFile = new RandomAccessFile(new File(sdFile, "pb.txt"), "rwd");pbFile.writeBytes(pb_download.getMax()+";"+currentPb+";"+percent);pbFile.close();}}accessFile.close();is.close();runOnUiThread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "當前線程" + threadId + "---完成下載", 1).show();}});/** * 第五步:當你的n個線程都完成下載 的時候我才進行刪除記錄下載位置的快取檔案 */deleteRecordFile();} else {runOnUiThread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "server端返回錯誤", 1).show();}});}// 設定你下載檔案} catch (Exception e) {e.printStackTrace();}}}/** * synchronized避免線程同步 下載完刪除隱藏檔下載位置的暫時檔案 */public synchronized void deleteRecordFile() {// 外部存放裝置的路徑File sdFile = Environment.getExternalStorageDirectory();// 線程下載完就減去threadRunning--;// 當沒有正在執行的線程if (threadRunning == 0) {for (int i = 1; i <= 3; i++) {File recordFile = (new File(sdFile, i + ".txt"));if (recordFile.exists()) {recordFile.delete();}File pbFile = (new File(sdFile, "pb.txt"));if (pbFile.exists()) {pbFile.delete();}}}}}
補充知識點
不用在給進度條設定值的時候考慮同步。由於android定義progressBar的時候已經 設定了同步
2.當程式有多個線程訪問一個變數,能夠用synchronized解決
synchronized (MainActivity.this) {//進度條當前進度currentPb += len;pb_download.setProgress(currentPb);runOnUiThread(new Runnable() {@Overridepublic void run() {tv_pb.setText("當前的進度是:"+currentPb*100/pb_download.getMax()+"%");}});
執行結果
1.當檔案下載時,進度條顯示和當前進度顯示
2.當又一次載入時繼續上次下載
3.當檔案進行下載時,暫時儲存下載檔案位置的pb.txt被建立
4.當線程完成下載後,在主線程Toast完成下載
5.當下在完畢後進度條走滿,當前進度為100%
6.下載完後,暫時檔案銷毀
源碼:http://download.csdn.net/detail/zhaoyazhi2129/7406731
轉寄請標明出處:http://blog.csdn.net/zhaoyazhi2129/article/details/27192169
趙雅智_android多線程下載帶進度條