編輯:Android開發實例
多線程下載大概思路就是通過Range 屬性實現文件分段,然後用RandomAccessFile 來讀寫文件,最終合並為一個文件
首先看下效果圖
創建工程 ThreadDemo
首先布局文件 threaddemo.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="下載地址"
- />
- <TextView
- android:id="@+id/downloadurl"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:lines="5"
- />
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="線程數"
- />
- <EditText
- android:id="@+id/downloadnum"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- <ProgressBar
- android:id="@+id/downloadProgressBar"
- android:layout_width="fill_parent"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_height="wrap_content"
- />
- <TextView
- android:id="@+id/downloadinfo"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="下載進度 0"
- />
- <Button
- android:id="@+id/downloadbutton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="開始下載"
- />
- </LinearLayout>
主界面 Acitivity
- public class ThreadDownloadDemo extends Activity {
- private TextView downloadurl;
- private EditText downloadnum;
- private Button downloadbutton;
- private ProgressBar downloadProgressBar;
- private TextView downloadinfo;
- private int downloadedSize = 0;
- private int fileSize = 0;
- private long downloadtime;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.threaddemo);
- downloadurl = (TextView) findViewById(R.id.downloadurl);
- downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3");
- downloadnum = (EditText) findViewById(R.id.downloadnum);
- downloadinfo = (TextView) findViewById(R.id.downloadinfo);
- downloadbutton = (Button) findViewById(R.id.downloadbutton);
- downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
- downloadProgressBar.setVisibility(View.VISIBLE);
- downloadProgressBar.setMax(100);
- downloadProgressBar.setProgress(0);
- downloadbutton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- download();
- downloadtime = SystemClock.currentThreadTimeMillis();
- }
- });
- }
- private void download() {
- // 獲取SD卡目錄
- String dowloadDir = Environment.getExternalStorageDirectory()
- + "/threaddemodownload/";
- File file = new File(dowloadDir);
- //創建下載目錄
- if (!file.exists()) {
- file.mkdirs();
- }
- //讀取下載線程數,如果為空,則單線程下載
- int downloadTN = Integer.valueOf("".equals(downloadnum.getText()
- .toString()) ? "1" : downloadnum.getText().toString());
- String fileName = "hetang.mp3";
- //開始下載前把下載按鈕設置為不可用
- downloadbutton.setClickable(false);
- //進度條設為0
- downloadProgressBar.setProgress(0);
- //啟動文件下載線程
- new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer
- .valueOf(downloadTN), dowloadDir + fileName).start();
- }
- Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- //當收到更新視圖消息時,計算已完成下載百分比,同時更新進度條信息
- int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
- if (progress == 100) {
- downloadbutton.setClickable(true);
- downloadinfo.setText("下載完成!");
- Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this)
- .setTitle("提示信息")
- .setMessage("下載完成,總用時為:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")
- .setNegativeButton("確定", new DialogInterface.OnClickListener(){
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- })
- .create();
- mdialog.show();
- } else {
- downloadinfo.setText("當前進度:" + progress + "%");
- }
- downloadProgressBar.setProgress(progress);
- }
- };
- public class downloadTask extends Thread {
- private int blockSize, downloadSizeMore;
- private int threadNum = 5;
- String urlStr, threadNo, fileName;
- public downloadTask(String urlStr, int threadNum, String fileName) {
- this.urlStr = urlStr;
- this.threadNum = threadNum;
- this.fileName = fileName;
- }
- @Override
- public void run() {
- FileDownloadThread[] fds = new FileDownloadThread[threadNum];
- try {
- URL url = new URL(urlStr);
- URLConnection conn = url.openConnection();
- //防止返回-1
- InputStream in = conn.getInputStream();
- //獲取下載文件的總大小
- fileSize = conn.getContentLength();
- Log.i("bb", "======================fileSize:"+fileSize);
- //計算每個線程要下載的數據量
- blockSize = fileSize / threadNum;
- // 解決整除後百分比計算誤差
- downloadSizeMore = (fileSize % threadNum);
- File file = new File(fileName);
- for (int i = 0; i < threadNum; i++) {
- Log.i("bb", "======================i:"+i);
- //啟動線程,分別下載自己需要下載的部分
- FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);
- fdt.setName("Thread" + i);
- fdt.start();
- fds[i] = fdt;
- }
- boolean finished = false;
- while (!finished) {
- // 先把整除的余數搞定
- downloadedSize = downloadSizeMore;
- finished = true;
- for (int i = 0; i < fds.length; i++) {
- downloadedSize += fds[i].getDownloadSize();
- if (!fds[i].isFinished()) {
- finished = false;
- }
- }
- handler.sendEmptyMessage(0);
- //線程暫停一秒
- sleep(1000);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
這裡啟動線程將文件分割為幾個部分,每一個部分再啟動一個線程去下載數據
下載文件的線程
- public class FileDownloadThread extends Thread{
- private static final int BUFFER_SIZE=1024;
- private URL url;
- private File file;
- private int startPosition;
- private int endPosition;
- private int curPosition;
- //標識當前線程是否下載完成
- private boolean finished=false;
- private int downloadSize=0;
- public FileDownloadThread(URL url,File file,int startPosition,int endPosition){
- this.url=url;
- this.file=file;
- this.startPosition=startPosition;
- this.curPosition=startPosition;
- this.endPosition=endPosition;
- }
- @Override
- public void run() {
- BufferedInputStream bis = null;
- RandomAccessFile fos = null;
- byte[] buf = new byte[BUFFER_SIZE];
- URLConnection con = null;
- try {
- con = url.openConnection();
- con.setAllowUserInteraction(true);
- //設置當前線程下載的起止點
- con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
- Log.i("bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-" + endPosition);
- //使用java中的RandomAccessFile 對文件進行隨機讀寫操作
- fos = new RandomAccessFile(file, "rw");
- //設置寫文件的起始位置
- fos.seek(startPosition);
- bis = new BufferedInputStream(con.getInputStream());
- //開始循環以流的形式讀寫文件
- while (curPosition < endPosition) {
- int len = bis.read(buf, 0, BUFFER_SIZE);
- if (len == -1) {
- break;
- }
- fos.write(buf, 0, len);
- curPosition = curPosition + len;
- if (curPosition > endPosition) {
- downloadSize+=len - (curPosition - endPosition) + 1;
- } else {
- downloadSize+=len;
- }
- }
- //下載完成設為true
- this.finished = true;
- bis.close();
- fos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public boolean isFinished(){
- return finished;
- }
- public int getDownloadSize() {
- return downloadSize;
- }
- }
這裡通過RandomAccessFile 的seek方法定位到相應的位置 並實時記錄下載量
當然這裡需要聯網和訪問SD卡 所以要加上相應的權限
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
系統啟動過程圖: Framework層所有的Service都是運行在SystemServer進程中;SystemServer進程是由Zygote進程創
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我