編輯:關於Android編程
本案例在於實現文件的多線程斷點下載,即文件在下載一部分中斷後,可繼續接著已有進度下載,並通過進度條顯示進度。也就是說在文件開始下載的同時,自動創建每個線程的下載進度的本地文件,下載中斷後,重新進入應用點擊下載,程序檢查有沒有本地文件的存在,若存在,獲取本地文件中的下載進度,繼續進行下載,當下載完成後,自動刪除本地文件。
1. 定義布局文件需要用到的屬性名及內容

2. 設置用戶的Internet權限和關於SD卡的權限
3. 開始界面的布局
基本效果圖如下:

用到兩個TextView控件,一個EditText控件,一個Button控件,一個ProgressBar控件<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+0OjSqtei0uK1xMrHo7q9+LbIzPXTwzxQcm9ncmVzc0JhciAvPr/YvP6jrMno1sNzeXRsZcr00NSjunN0eWxlPQ=="?android:attr/progressBarStyleHorizontal"
4.MainActivity的主要程序如下,代碼中有注釋詳解:
package www.csdn.net.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 www.csdn.net.utils.StreamTools;
import android.R.integer;
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;
public class DownloadActivity extends Activity {
// 線程開啟的數量
private int threadNum = 3;
private int threadRunning = 3;
private EditText et_url;
private ProgressBar progressBar;
private TextView tv_pb;
private int currentProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
// 獲取控件對象
et_url = (EditText) findViewById(R.id.et_url);
progressBar = (ProgressBar) findViewById(R.id.pb_down);
tv_pb = (TextView) findViewById(R.id.tv_pb);
File sdDir = Environment.getExternalStorageDirectory();
File pbFile = new File(sdDir,"pb.txt");
InputStream is = null;
try {
//判斷文件是否存在
if (pbFile.exists()) {
is = new FileInputStream(pbFile);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (is != null) {
String value = StreamTools.streamToStr(is);
String[] arr = value.split(";");
progressBar.setMax(Integer.valueOf(arr[0]));//最大值
currentProgress = Integer.valueOf(arr[1]);//當前值
progressBar.setProgress(currentProgress);
tv_pb.setText("當前的進度是:"+arr[2]);//顯示百分比
}
}
// 下載文件(得到服務器端文件的大小)
public void downLoadFile(View v) {
// 獲取下載路徑
final String spec = et_url.getText().toString();
if (TextUtils.isEmpty(spec)) {
Toast.makeText(this, "下載的地址不能為空", Toast.LENGTH_LONG).show();
} else {
new Thread() {
public void run() {
// HttpURLConnection
try {
// 根據下載的地址構建URL對象
URL url = new URL(spec);
// 通過URL對象的openConnection()方法打開連接,返回一個連接對象
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 設置請求的頭
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setReadTimeout(5000);
httpURLConnection.setConnectTimeout(5000);
// 判斷是否響應成功
if (httpURLConnection.getResponseCode() == 200) {
// 獲取下載文件的長度
int fileLength = httpURLConnection
.getContentLength();
//設置進度條的最大值
progressBar.setMax(fileLength);
//判斷sd卡是否管用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 保存文件
// 外部存儲設備的路徑
File sdFile = Environment
.getExternalStorageDirectory();
//獲取文件的名稱
String fileName = spec.substring(spec.lastIndexOf("/")+1);
//創建保存的文件
File file = new File(sdFile, fileName);
//創建可以隨機訪問對象
RandomAccessFile accessFile = new RandomAccessFile(
file, "rwd");
// 保存文件的大小
accessFile.setLength(fileLength);
// 關閉
accessFile.close();
// 計算出每個線程的下載大小
int threadSize = fileLength / threadNum;
// 計算出每個線程的開始位置,結束位置
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).start();
}
}else {
DownloadActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(DownloadActivity.this, "SD卡不管用", Toast.LENGTH_LONG).show();
}
});
}
}else {
//在主線程中運行
DownloadActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(DownloadActivity.this, "服務器端返回錯誤", Toast.LENGTH_LONG).show();
}
});
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
};
}.start();
}
}
class DownLoadThread extends Thread {
private int threadId;
private int startIndex;
private int endIndex;
private String path;
/**
* 構造函數
*
* @param threadId
* 線程的序號
* @param startIndex
* 線程開始位置
* @param endIndex
* @param path
*/
public DownLoadThread(int threadId, int startIndex, int endIndex,
String path) {
super();
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.path = path;
}
@Override
public void run() {
try {
File sdFile = Environment.getExternalStorageDirectory();
//獲取每個線程下載的記錄文件
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對象的openConnection()方法打開連接,返回一個連接對象
HttpURLConnection httpURLConnection = (HttpURLConnection) url
.openConnection();
// 設置請求的頭
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setReadTimeout(5000);
// 設置下載文件的開始位置結束位置
httpURLConnection.setRequestProperty("Range", "bytes="
+ startIndex + "-" + endIndex);
// 獲取的狀態碼
int code = httpURLConnection.getResponseCode();
// 判斷是否成功
if (code == 206) {
// 獲取每個線程返回的流對象
InputStream is = httpURLConnection.getInputStream();
//獲取文件的名稱
String fileName = path.substring(path.lastIndexOf("/")+1);
// 根據路徑創建文件
File file = new File(sdFile, fileName);
// 根據文件創建RandomAccessFile對象
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.seek(startIndex);
// 定義讀取的長度
int len = 0;
// 定義緩沖區
byte b[] = new byte[1024 * 1024];
int total = 0;
// 循環讀取
while ((len = is.read(b)) != -1) {
RandomAccessFile threadFile = new RandomAccessFile(
new File(sdFile, threadId + ".txt"), "rwd");
threadFile.writeBytes((startIndex + total) + "");
threadFile.close();
raf.write(b, 0, len);
// 已經下載的大小
total += len;
//解決同步問題
synchronized (DownloadActivity.this) {
currentProgress += len;
progressBar.setProgress(currentProgress);
//計算百分比的操作 l表示long型
final String percent = currentProgress*100l/progressBar.getMax()+"%";
DownloadActivity.this.runOnUiThread(new Runnable() {
public void run() {
tv_pb.setText("當前的進度是:"+percent);
}
});
//創建保存當前進度和百分比的操作
RandomAccessFile pbFile = new RandomAccessFile(
new File(sdFile, "pb.txt"), "rwd");
pbFile.writeBytes(progressBar.getMax()+";"+currentProgress+";"+percent);
pbFile.close();
}
}
raf.close();
is.close();
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(DownloadActivity.this, "當前線程--" + threadId + "--下載完畢", Toast.LENGTH_LONG).show();
}
});
deleteRecordFiles();
} else {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(DownloadActivity.this, "服務器端下載錯誤", Toast.LENGTH_LONG).show();
}
});
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// synchronized避免線程同步
public synchronized void deleteRecordFiles() {
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();
}
}
}
}
}
對於流的輸出可以封裝一個StreamTools方法,在主程序中可以應用,代碼如下:
package www.csdn.net.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class StreamTools {
public static String streamToStr(InputStream is){
String value = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 定義讀取的長度
int len = 0;
// 定義緩沖區
byte b[] = new byte[1024];
// 循環讀取
while ((len = is.read(b)) != -1) {
baos.write(b, 0, len);
}
baos.close();
is.close();
value = new String(baos.toByteArray());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return value;
}
}
5. 程序運行結果如圖:


sd卡中出現的臨時文件,當下載完成會自動刪除:

6. 出現的bug原因可能有:
Internet權限沒加,服務器沒啟動,訪問下載路徑有錯,沒有獲取控件對象等。
如果文件下載中,進度條顯示的進度是負數,可能原因是文件大小進行百分比計算時超出內存空間,解決辦法:在定義百分比的時候,在100後面加上l,表示long型,即String percent = currentProgress*100l/progressBar.getMax()+"%"。
基於Android移動終端的微型餐飲管理系統的設計與實現2-側滑菜單
今天我先來寫一下側滑菜單,如圖: 側滑菜單的實現方法有很多,網上也有完整的開源框架,現在如果用Android Studio開發的話,一開始選模板的時候就可以選擇
Android TabActivity使用方法
TabActivity 首先Android裡面有個名為TabActivity來給我們方便使用。其中有以下可以關注的函數: public TabHost getT
ES文件浏覽器怎麼添加其他雲
ES文件浏覽器怎麼添加其他雲。ES文件浏覽器是一個能管理手機本地、局域網共享、FTP和藍牙文件的管理器。他有自己的個人雲,那我想添加其他的雲,怎麼辦呢?是不
android CoordinatorLayout使用
一、CoordinatorLayout有什麼作用CoordinatorLayout作為“super-powered FrameLayout”基本實