編輯:關於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 Studio開發的話,一開始選模板的時候就可以選擇
TabActivity 首先Android裡面有個名為TabActivity來給我們方便使用。其中有以下可以關注的函數: public TabHost getT
ES文件浏覽器怎麼添加其他雲。ES文件浏覽器是一個能管理手機本地、局域網共享、FTP和藍牙文件的管理器。他有自己的個人雲,那我想添加其他的雲,怎麼辦呢?是不
一、CoordinatorLayout有什麼作用CoordinatorLayout作為“super-powered FrameLayout”基本實