編輯:Android開發實例
本文實例講述了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" 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>
<?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="下載地址" /> <TextViewandroid: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="線程數" /> <EditTextandroid:id="@+id/downloadnum"android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ProgressBarandroid:id="@+id/downloadProgressBar"android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextViewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下載進度 0"/> <Buttonandroid: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 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; @Overridepublic 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() {@Overridepublic 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(){@Overridepublic 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; } @Overridepublic 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; } } 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; } @Overridepublic 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> <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
這樣就OK了 下面可以看看斷點續傳的問題了。有待測試~~
希望本文所述對大家的Android程序設計有所幫助。
在Android中,可以有多種方式來實現網絡編程: 創建URL,並使用URLConnection/HttpURLConnection 使用HttpClient使用
JSON代表JavaScript對象符號。它是一個獨立的數據交換格式,是XML的最佳替代品。本章介紹了如何解析JSON文件,並從中提取所需的信息。Android提供了四個
以前也模仿者ireader實現了書架的效果,但是那種是使用listview實現的,並不好用。絕大多數都是用gridview實現的,網上這方面資料比較少,有些開源的
這個是網易新聞的主界面,我們知道底部可以用tabhost實現,這個很容易,我們在其他軟件中也會經常用到。 至於頂部的滑動條,個人感覺還是比較漂亮的所以今天也模仿了