(掌握)httpclient的get和post
HttpClient:他是android集成的一个三方框架 Http框架
HttpClient在URL 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;
}
(掌握)get、post提交数据的中文乱码处理
get请求
浏览器进行URL编码
服务器:
中文乱码问题:
浏览器:UTF-8
服务器:tomcat ISO-8859-1
使用HttpClient框架是不会乱码。
那么HttpClient使用的编码:UTF-8
(了解)asyncHttpClient的使用
asyncHttpClient
async:异步 开了一个线程
HttpClient:使用Http协议的客户端
他对HttpClient进行了封装:
Thread +HttpClient
不用再开线程。
把AsyncHttpClient的源码添加到工程
(掌握)文件上传
1 把服务上调试通过
文件上传:业务操作 也要使用开源项目 FileUpload
2 客户端
(掌握)文件下载
原理:
请求服务器的资源,服务器回送该文件的文件流,把流保存在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;
}
}
(掌握)多线程下载原理
多线程下载比单线程下载:速度更快
为什么?
多条线程可以增加服务器的带宽。 服务器那边的响应对象变多
抢占服务器的资源变多。
未知:
1 文件的大小
联网获取文件的大小,只需要服务器告诉我文件的大小,不需要文件流
只要响应的头信息:
HttpHead2 请求服务器指定范围的数据
Http协议他可以指定范围:
key:Range value: bytes:start-end
3 把服务返回的数据正确的写入到指定的位置
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多线程下载 出现下载进度条
进度条 操作:
1 设置最大值 setMax(filelength);
2 更新进度 setProgress()
下载百分比 操作
1 更新 setText("") 根据 最大值 和 当前的下载量的对比
Handler + Message来实现
(掌握)android多线程断点下载
暂停下载
1 点击下载按钮状态的切换
2 暂停
控制3条下载的子线程:让三条线程都停止下载
3 继续下载
记录原来每条线程的下载量。文件来记录
规范:0.txt
4 点击继续下载
实现代码
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框架 (智能北京)