Android中的Http通信(四)之多線程下載數據

如果你還想了解Http的基礎知識、通過url獲取網絡數據以及GET、POST方式上傳數據到服務器,請查看我前面幾篇博文。Android中的Http通信(一)之Http協議基本知識Android中的Http通信(二)之根據Url讀取網絡數據Android中的Http通信(三)之get、post傳遞參數到服務器

本文主要介紹通過多線程的方式從服務器下載數據,這和前兩篇博文相比較,增加了線程池以及本地文件讀寫。如果內心看完前面的幾篇博文,這一篇文章,就顯得很容易啦。廢話不多說,直接開幹。

老規矩,先來一個簡單的佈局,這個佈局裏面只有一個button和imageview,這裏不做任何解釋:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/download_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="下載" />

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/download_btn"
        android:layout_centerHorizontal="true"
        android:background="@drawable/ic_launcher"
        android:scaleType="centerCrop" />

</RelativeLayout>

再來看一下Activity中的代碼:

package com.example.http;

import java.io.File;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

/**
 * 文件下載
 * 
 * @author xiaoyf
 * 
 */
public class MainActivity extends Activity {
	private String fileName;
	private ImageView img;
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				Bitmap bitmap = BitmapFactory.decodeFile(fileName);
				img.setImageBitmap(bitmap);
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		File parent = Environment.getExternalStorageDirectory();
		File file = new File(parent, System.currentTimeMillis() + ".jpg");
		fileName = file.getAbsolutePath();
		initViews();
	}

	/**
	 * 初始化控件
	 */
	private void initViews() {
		img = (ImageView) findViewById(R.id.img);
		findViewById(R.id.download_btn).setOnClickListener(
				new OnClickListener() {

					@Override
					public void onClick(View arg0) {
						// TODO Auto-generated method stub
						new Thread() {
							@Override
							public void run() {
								DownLoadFile downLoadFile = new DownLoadFile(
										"http://192.168.197.2:8080/WebProject/girl.jpg",
										handler, fileName);
								downLoadFile.downLoad();
							}
						}.start();
					}
				});

	}

}
同樣是簡單,不做任何解釋得意得意得意

下面是核心代碼,下載操作都在這裏面執行:

package com.example.http;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import android.os.Handler;

/**
 * 文件下載
 * 
 * @author xiaoyf
 * 
 */
public class DownLoadFile {
	/**
	 * 線程池中線程的數量
	 */
	private static final int THREAD_NUM = 3;
	/**
	 * 連接超時時間、讀取超時時間
	 */
	private static final int TIME_OUT = 5000;
	/**
	 * 完成的線程的數量
	 */
	private int complete_num;
	/**
	 * 線程池
	 */
	private Executor executorThread = Executors.newFixedThreadPool(THREAD_NUM);

	private String url;
	private Handler handler;
	private String fileName;

	public DownLoadFile() {
		super();
	}

	public DownLoadFile(String url, Handler handler, String fileName) {
		super();
		this.url = url;
		this.handler = handler;
		this.fileName = fileName;
	}

	public void downLoad() {
		try {
			URL httpUrl = new URL(url);
			HttpURLConnection connection = (HttpURLConnection) httpUrl
					.openConnection();
			connection.setReadTimeout(TIME_OUT);
			connection.setConnectTimeout(TIME_OUT);
			connection.setRequestMethod("GET");
			connection.setDoInput(true);
			long count = connection.getContentLength();
			long block = count / THREAD_NUM;
			// 計算每個線程下載的起始位置和結束位置;
			// 如:待下載的內容有10字節:第一個線程:0-2;第二個線程:3-5;第三個線程:6-10
			for (int i = 0; i < THREAD_NUM; i++) {
				long start = i * block;
				long end = (i + 1) * block - 1;
				if (i == THREAD_NUM - 1) {
					end = count;
				}
				DownLoadRunnable runnable = new DownLoadRunnable(start, end);
				executorThread.execute(runnable);
			}

		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	class DownLoadRunnable implements Runnable {
		private long start;
		private long end;

		public DownLoadRunnable() {

		}

		public DownLoadRunnable(long start, long end) {
			this.start = start;
			this.end = end;
		}

		public void run() {
			try {
				URL httpUrl = new URL(url);
				HttpURLConnection connection = (HttpURLConnection) httpUrl
						.openConnection();
				connection.setReadTimeout(TIME_OUT);
				connection.setConnectTimeout(TIME_OUT);
				connection.setRequestMethod("GET");
				connection.setDoInput(true);
				// 通過http的Range字段,設置從服務器請求數據的開始位置和結束位置
				connection.setRequestProperty("Range", "bytes=" + start + "-"
						+ end);
				// 創建RandomAccessFile對象,"rwd"代表可以對文件進行讀寫和操作
				RandomAccessFile accessFile = new RandomAccessFile(new File(
						fileName), "rwd");
				// 通過RandomAccessFile對象,設置文件開始寫入的位置
				accessFile.seek(start);

				InputStream in = connection.getInputStream();
				//定義一個緩衝數組,大小爲2K
				byte[] buffer = new byte[1024 * 2];
				int len = 0;
				while ((len = in.read(buffer)) != -1) {
					accessFile.write(buffer, 0, len);
				}

				if (in != null) {
					in.close();
				}
				if (accessFile != null) {
					accessFile.close();
				}
				complete_num++;
				if (complete_num == THREAD_NUM) {
					handler.sendEmptyMessage(1);
				}

			} catch (MalformedURLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
註釋的也是相當詳細,不做過多解釋。文章最後結束的時候,會做一個流程的總結。OK,我們來看一下運行的效果如何。


看着是不是爽歪歪啊羨慕羨慕羨慕

從美女身上回來,我們最後進行一下流程總結:

1、通過給定的url獲得URL以及HttpURLConnection對象,並對HttpURLConnection對象進行基本的設置

2、根據線程池中線程的數量,計算每個線程下載的起始位置和結束位置

3、對線程進行必要的設置,其中包括通過給定的url獲得URL以及HttpURLConnection對象,並對HttpURLConnection對象進行基本的設置(特別是通過http的Range字段,設置從服務器請求數據的開始位置和結束位置)、創建RandomAccessFile對象,通過RandomAccessFile對象,設置文件開始寫入的位置、

4、啓動線程池中各個線程,進行獨立下載。

5、記錄完成的線程的數量,當完成的線程的數量和線程池中線程的數量相等時,文件下載完畢


項目下載:http://download.csdn.net/detail/u014544193/9415691

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章