Android中的Http通信(四)之多线程下载数据

本文介绍了如何在Android中使用多线程和线程池从服务器下载数据,涉及HttpURLConnection、文件读写及线程间协调。通过设定线程下载的起始和结束位置,利用Range字段实现断点续传,同时提供了项目源码下载链接。
摘要由CSDN通过智能技术生成

如果你还想了解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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值