android多线程下载

(掌握)httpclient的get和post

HttpClient:他是android集成的一个三方框架 Http框架

HttpClientURL  HttpClient再次进行了oop的封装

HttpClient:他就是一个浏览器  

执行请求  回送响应

HttpClient:浏览器   方法:执行  响应 HttpReponse exeucute(请求HttpUriRequest)








/**
	 * 使用HttpClient框架 以GET请求提交数据到服务器
	 * @param map 数据
	 * @param path 请求路径
	 * @return
	 * @throws Exception
	 */
	public static boolean doHttpClientGet(Map<String, String> map, String path) throws Exception{
		//特点:http://localhost:8080/web/LoginServlet?name=itcast&pwd=234
		//拼接uri
		StringBuffer sb = new StringBuffer(path);
		sb.append("?");
		for(Map.Entry<String, String> entry:map.entrySet()){
			String key = entry.getKey();
			String value = entry.getValue();
			sb.append(key).append("=").append(value);
			sb.append("&");
		}
		//删除最后一个&
		sb.deleteCharAt(sb.length()-1);
		//浏览器
		HttpClient httpClient = new DefaultHttpClient();
		//get请求对象
		HttpGet request = new HttpGet(sb.toString());
		//执行请求
		HttpResponse response = httpClient.execute(request);
		//判断响应码是否为200
		if(response.getStatusLine().getStatusCode() == 200){
			//获取服务器回送的流
			InputStream inputStream = response.getEntity().getContent();
			//返回 success  or  error
			String content = changeStreamToString(inputStream);
			if("success".equals(content)){
				return true;
			}else{
				return false;
			}
		}
		return false;
	}

post请求

/**
	 * 使用HttpClient框架 以POST请求提交数据到服务器
	 * @param map 数据
	 * @param path 请求路径
	 * @return
	 * @throws Exception
	 */
	public static boolean doHttpClientPost(Map<String, String> map, String path) throws Exception{
		//post请求:请求实体
		HttpClient client = new DefaultHttpClient();//浏览器
		HttpPost request = new HttpPost(path);//post请求对象
		//实体参数
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		for(Map.Entry<String, String> entry:map.entrySet()){
			String name = entry.getKey();
			String value = entry.getValue();
			NameValuePair nvp = new BasicNameValuePair(name, value);
			parameters.add(nvp);
		}
		//实体
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters, "utf-8");
		//把实体设置给请求对象
		request.setEntity(entity);
		//执行请求
		HttpResponse response = client.execute(request);
		//判断响应码是否为200
		if(response.getStatusLine().getStatusCode() == 200){
			//获取服务器回送的流
			InputStream inputStream = response.getEntity().getContent();
			//返回 success  or  error
			String content = changeStreamToString(inputStream);
			if("success".equals(content)){
				return true;
			}else{
				return false;
			}
		}
		return false;
	}
(掌握)getpost提交数据的中文乱码处理

get请求


浏览器进行URL编码

 服务器:


中文乱码问题:

浏览器:UTF-8

服务器:tomcat  ISO-8859-1


使用HttpClient框架是不会乱码。

那么HttpClient使用的编码:UTF-8

(了解)asyncHttpClient的使用

asyncHttpClient

async:异步   开了一个线程

HttpClient:使用Http协议的客户端   

他对HttpClient进行了封装:

Thread +HttpClient  

不用再开线程。

AsyncHttpClient的源码添加到工程



(掌握)文件上传

把服务上调试通过

  文件上传:业务操作  也要使用开源项目  FileUpload 


客户端


(掌握)文件下载


原理:

请求服务器的资源,服务器回送该文件的文件流,把流保存在android手机的sdcard.


public class MainActivity extends Activity {

	public static final int SUCCESS_LOAD_DATA = 0;
	private ImageView iv;
	private Button bt_set;
	private File file;
	
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SUCCESS_LOAD_DATA:
				Uri uri = (Uri) msg.obj;
				iv.setImageURI(uri);
				//图片下载成功
				//设置按钮可用
				bt_set.setEnabled(true);
				break;

			default:
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		iv = (ImageView) findViewById(R.id.iv);
		bt_set = (Button) findViewById(R.id.bt_set);
		
	}
	
	public void download(View v){
		//从服务器上下载图片   http://10.0.2.2:8080/08web/tokhot4.JPG   
		//使用api:  Thread   权限      HttpClient    Environment 
		//目的:把图片下载到sdcard
		new Thread(new MyTask()).start();
	}
	private class MyTask implements Runnable{

		//下载图片
		@Override
		public void run() {
			
			String path = "http://10.0.2.2:8080/08web/tokhot4.JPG";
			try {
				//客户端
				HttpClient client = new DefaultHttpClient();
				//请求对象
				HttpGet request = new HttpGet(path);
				//执行请求 获取响应对象
				HttpResponse response = client.execute(request);
				//判断响应是否成功
				if(response.getStatusLine().getStatusCode() == 200){
					//获取服务器回送的流
					InputStream inputStream = response.getEntity().getContent();
					
					//把流保存成文件
					String name = getFileName(path);
					file = new File(Environment.getExternalStorageDirectory(),name);
					FileOutputStream fos = new FileOutputStream(file);
					byte[] buffer = new byte[1024];
					int len = 0;
					while((len = inputStream.read(buffer)) != -1){
						fos.write(buffer, 0, len);
					}
					fos.close();
					inputStream.close();
					
					//显示图片
					Uri uri = Uri.fromFile(file);//获取文件的uri
					Message msg = Message.obtain(mHandler, SUCCESS_LOAD_DATA, uri);
					msg.sendToTarget();
					
				}else{
					alertUser("下载失败");
				}
			} catch (Exception e) {
				e.printStackTrace();
				alertUser("下载失败");
			}
		}
		
	}
	
	
	public void set(View v){
			new Thread(){
				public void run() {
					try {
						/*//设置墙纸
						Drawable drawable = iv.getDrawable();
						//请求问Drawable如何转换成bitmap
						*/
						Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
						setWallpaper(bitmap); //设置墙纸是一个耗时的操作     开线程
						alertUser("设置成");
					} catch (Exception e) {
						e.printStackTrace();
						alertUser("设置失败");
					}
				};
			}.start();
			

	}

	/**
	 * 根据网络路径获取文件名称
	 * @param path
	 * @return
	 */
	private String getFileName(String path){
		return path.substring(path.lastIndexOf("/")+1);
	}
	
	
	private void alertUser(final String text){
		runOnUiThread(new Runnable() {
			
			@Override
			public void run() {
				Toast.makeText(getApplicationContext(), text, 0).show();
			}
		});
	}
	
	/**
	 * 把Drawable转换成Bitmap
	 * @param drawable
	 * @return
	 */
	public static Bitmap drawableToBitmap(Drawable drawable) {

        if (null == drawable) {
            return null;
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Config config = (drawable.getOpacity() != PixelFormat.OPAQUE) ? Config.ARGB_8888
                : Config.RGB_565;

        Bitmap bitmap = null;

        try {
            bitmap = Bitmap.createBitmap(width, height, config);
        } catch (OutOfMemoryError e) {

        }

        if (null != bitmap) {
            Rect oldRect = drawable.getBounds();
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, width, height);
            drawable.draw(canvas);
            drawable.setBounds(oldRect);
        }

        return bitmap;
    }


}

(掌握)多线程下载原理

多线程下载比单线程下载:速度更快

为什么?

多条线程可以增加服务器的带宽。  服务器那边的响应对象变多 

抢占服务器的资源变多。


未知:

文件的大小

  联网获取文件的大小,只需要服务器告诉我文件的大小,不需要文件流

  只要响应的头信息:

HttpHead

请求服务器指定范围的数据

  Http协议他可以指定范围:

  key:Range  value: bytes:start-end  

把服务返回的数据正确的写入到指定的位置

  RandomAccessFile 随机访问文件  


(掌握)android多线程下载

获取服务器上文件的大小


在客户创建和服务器大小一样的文件



计算block每条线程的下载量


开启三条线程下载


下载线程

/**
	 * 下载线程的参数:
	 * 下载的资源 path
	 * 每条线程的下载量block
	 * 下载线程的id threadid
	 * 下载文件的存放位置  file
	 * 可以通过:block  threadid  计算出开始位置  和结束位置
	 *
	 */
	private class DownloadThread extends Thread{
		private String path;
		private int block;
		private int threadid;
		private File file;
		private int start;//开始位置
		private int end;//结束位置
		
		public DownloadThread(String path, int block, int threadid, File file) {
			super();
			this.path = path;
			this.block = block;
			this.threadid = threadid;
			this.file = file;
			//计算下载线程的开始位置和结束位置
			start = threadid*block;
			end = (threadid + 1)*block - 1;
		}


		@Override
		public void run() {
			super.run();
			try {
				//执行分段下载
				HttpClient client = new DefaultHttpClient();
				HttpGet request = new HttpGet(path);
				//设置下载的范围
				request.addHeader("Range", "bytes:"+start+"-"+end);
				HttpResponse response = client.execute(request);
				//分段下载服务器的响应码是:206
				if(response.getStatusLine().getStatusCode() == 206){
					InputStream inputStream = response.getEntity().getContent();
					
					RandomAccessFile raf = new RandomAccessFile(file, "rwd");
					//跳转到要写入的位置
					raf.seek(start);
					
					//把数据写入到文件
					byte[] buffer = new byte[1024];
					int len = 0;
					while((len = inputStream.read(buffer)) != -1){
						raf.write(buffer, 0, len);
					}
					raf.close();
					inputStream.close();
					
					Log.i(TAG, "第"+threadid+"线程下载完成");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
(掌握)android多线程下载 出现下载进度条

进度条 操作:

设置最大值  setMax(filelength);  

更新进度  setProgress()  

下载百分比  操作

更新   setText("")  根据  最大值  和 当前的下载量的对比  

 

Handler + Message来实现

(掌握)android多线程断点下载

暂停下载

点击下载按钮状态的切换

 

暂停

  控制3条下载的子线程:让三条线程都停止下载 


继续下载

 记录原来每条线程的下载量。文件来记录

 规范:0.txt 


点击继续下载




实现代码

package cn.itcast.wh08.multithreaddownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.RandomAccessFile;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

	protected static final String TAG = "MainActivity";
	
	//下载线程的数量
	private final static int threadsize = 3;

	protected static final int SET_MAX = 0;
	public static final int UPDATE_VIEW = 1;

	private EditText et_path;

	private ProgressBar pb;

	private TextView tv_info;
	
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SET_MAX://设置进度条的最大值
				int filelength = msg.arg1;
				pb.setMax(filelength);
				break;
			case UPDATE_VIEW://更新进度条  和 下载的比率
				int len = msg.arg1;//新下载的长度
				pb.setProgress(pb.getProgress()+len);//设置进度条的刻度
				
				int max = pb.getMax();//获取进度的最大值
				int progress = pb.getProgress();//获取已经下载的数据量
				//  下载:30    总:100
				int result = (progress*100)/max;
				
				tv_info.setText("下载:"+result+"%");
				
				break;

			default:
				break;
			}
		};
	};

	private Button bt_download;

	private Button bt_pause;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//找到控件
		et_path = (EditText) findViewById(R.id.et_path);
		pb = (ProgressBar) findViewById(R.id.pb);
		tv_info = (TextView) findViewById(R.id.tv_info);
		
		bt_download = (Button) findViewById(R.id.bt_download);
		bt_pause = (Button) findViewById(R.id.bt_pause);
		
		//数据的回显
		//确定下载的文件
		String uri = et_path.getText().toString().trim();
		String name = getFileName(uri);
		File file = new File(Environment.getExternalStorageDirectory(),name);
		//获取文件的大小
		int filelength = (int) file.length();
		pb.setMax(filelength);
		
		try {
			//统计原来所有的下载量
			int count = 0;
			//读取下载记录文件
			for(int threadid =0;threadid<threadsize;threadid++){
				//获取原来指定线程的下载记录
				int existDownloadLength = readDownloadInfo(threadid);
				count = count + existDownloadLength;
			}
			//设置进度条的刻度
			pb.setProgress(count);
			
			//计算比率
			int result = (count*100)/filelength;
			tv_info.setText("下载:"+result+"%");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	
	private boolean flag = false;//是否在下载
	
	public void pause(View v){
		flag = false;
		bt_download.setEnabled(true);
		bt_pause.setEnabled(false);
	}
	

	public void download(View v){
		flag = true;
		bt_download.setEnabled(false);
		bt_pause.setEnabled(true);
		new Thread(){//子线程
			public void run() {
				try {
					//获取服务器上文件的大小
					HttpClient client = new DefaultHttpClient();
					String uri = et_path.getText().toString().trim();
					HttpHead request = new HttpHead(uri);
					HttpResponse response = client.execute(request);
					//response  只有响应头  没有响应体
					if(response.getStatusLine().getStatusCode() == 200){
						Header[] headers = response.getHeaders("Content-Length");
						String value = headers[0].getValue();
						//文件大小
						int filelength = Integer.parseInt(value);
						Log.i(TAG, "filelength:"+filelength);
						
						//设置进度条的最大值
						Message msg_setmax = Message.obtain(mHandler, SET_MAX, filelength, 0);
						msg_setmax.sendToTarget();
						
						
						//处理下载记录文件
						for(int threadid=0;threadid<threadsize;threadid++){
							//对应的下载记录文件
							File file = new File(Environment.getExternalStorageDirectory(),threadid+".txt");
							//判断文件是否存在
							if(!file.exists()){
								//创建文件
								file.createNewFile();
							}
						}
						
						
						//在sdcard创建和服务器大小一样的文件
						String name = getFileName(uri);
						File file = new File(Environment.getExternalStorageDirectory(),name);
						//随机访问文件
						RandomAccessFile raf = new RandomAccessFile(file, "rwd");
						//设置文件的大小
						raf.setLength(filelength);
						//关闭
						raf.close();
						
						//计算每条线程的下载量
						int block = (filelength%threadsize == 0)?(filelength/threadsize):(filelength/threadsize+1);
						
						//开启三条线程执行下载
						for(int threadid=0;threadid<threadsize;threadid++){
							new DownloadThread(threadid, uri, file, block).start();
						}
						
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			};
		}.start();
	}
	
	
	//线程下载类
	private class DownloadThread extends Thread{
		private int threadid;//线程的id
		private String uri;//下载的地址
		private File file;//下载文件
		private int block;//下载的块
		private int start;
		private int end;
		
		public DownloadThread(int threadid, String uri, File file, int block) {
			super();
			this.threadid = threadid;
			this.uri = uri;
			this.file = file;
			this.block = block;
			//计算下载的开始位置和结束位置
			start = threadid * block;
			end = (threadid + 1)*block -1;
			
			try {
				//读取该条线程原来的下载记录
				int existDownloadLength = readDownloadInfo(threadid);
				
				//修改下载的开始位置
				start = start + existDownloadLength;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}



		//下载   状态码:200是普通的下载      206是分段下载        Range:范围
		@Override
		public void run() {
			super.run();
			try {
				RandomAccessFile raf = new RandomAccessFile(file, "rwd");
				//跳转到起始位置
				raf.seek(start);
				
				//分段下载
				HttpClient client = new DefaultHttpClient();
				HttpGet request = new HttpGet(uri);
				request.addHeader("Range", "bytes:"+start+"-"+end);//添加请求头
				HttpResponse response = client.execute(request);
				if(response.getStatusLine().getStatusCode() == 206){
					InputStream inputStream = response.getEntity().getContent();
					//把流写入到文件
					byte[] buffer = new byte[1024];
					int len = 0;
					while((len = inputStream.read(buffer)) != -1){
						//如果暂停下载   就直接return 
						if(!flag){
							return;//标准线程结束
						}
						//写数据
						raf.write(buffer, 0, len);
						
						//读取原来下载的数据量
						int existDownloadLength = readDownloadInfo(threadid);//原来下载的数据量
						
						//计算最新的下载
						int newDownloadLength = existDownloadLength + len;
						
						//更新下载记录
						updateDownloadInfo(threadid, newDownloadLength);
						
						//更新进度条的显示   下载的百分比
						Message update_msg = Message.obtain(mHandler, UPDATE_VIEW, len, 0);
						update_msg.sendToTarget();
						//模拟  看到进度条动的效果
						SystemClock.sleep(50);
					}
					inputStream.close();
					raf.close();
					Log.i(TAG, "第"+threadid+"条线程下载完成");
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 读取指定线程的下载数据量
	 * @param threadid  线程的id
	 * @return
	 * @throws Exception
	 */
	public int readDownloadInfo(int threadid) throws Exception{
		//下载记录文件
		File file = new File(Environment.getExternalStorageDirectory(),threadid+".txt");
		BufferedReader br = new BufferedReader(new FileReader(file));
		//读取一行数据
		String content = br.readLine();
		
		int downlength = 0;
		//如果该文件第一次创建去执行读取操作  文件里面的内容是 null
		if(!TextUtils.isEmpty(content)){
			downlength = Integer.parseInt(content);
		}
		//关闭流
		br.close();
		return downlength;
	}
	
	
	/**
	 * 更新下载记录
	 * @param threadid
	 * @param newDownloadLength
	 */
	public void updateDownloadInfo(int threadid,int newDownloadLength) throws Exception{
		//下载记录文件
		File file = new File(Environment.getExternalStorageDirectory(),threadid+".txt");
		FileWriter fw = new FileWriter(file);
		fw.write(newDownloadLength+"");
		fw.close();
	}
	
	/**
	 * 获取文件的名称
	 * @param uri
	 * @return
	 */
	private String getFileName(String uri){
		return uri.substring(uri.lastIndexOf("/")+1);
	}
}


(了解)开源项目多线程断点下载

Afinal框架  是一个中国人整合一些国外的框架。 一行搞定所有的事情

Afinal 框架  升级到了Xutils框架  (智能北京)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值