本帖最后由 allen927 于 2015-11-9 09:23 编辑
同样的课程、老师、就业,更好的学习环境,更低的学习成本! android基础Day05(多线程下载)
•(掌握)httpclient的get和postHttpClient:他是android集成的一个三方框架 Http框架 HttpClient在URL HttpClient再次进行了oop的封装 HttpClient:他就是一个浏览器 执行请求 回送响应 HttpClient:浏览器 方法:执行 响应 HttpReponse exeucute(请求HttpUriRequest)
/** * 使用HttpClient框架 以GET请求提交数据到服务器 * @param map 数据 * @param path 请求路径 * @return * @throws Exception */ publicstatic boolean doHttpClientGet(Map<String, String> map, String path)throws Exception{ //特点:http://localhost:8080/web/LoginServlet?name=itcast&pwd=234 //拼接uri StringBuffersb = new StringBuffer(path); sb.append("?"); for(Map.Entry<String,String> entry:map.entrySet()){ Stringkey = entry.getKey(); Stringvalue = 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 Stringcontent = changeStreamToString(inputStream); if("success".equals(content)){ returntrue; }else{ returnfalse; } } returnfalse; }
post请求 /** * 使用HttpClient框架 以POST请求提交数据到服务器 * @param map 数据 * @param path 请求路径 * @return * @throws Exception */ publicstatic boolean doHttpClientPost(Map<String, String> map, String path) throwsException{ //post请求:请求实体 HttpClientclient = new DefaultHttpClient();//浏览器 HttpPostrequest = new HttpPost(path);//post请求对象 //实体参数 List<NameValuePair>parameters = new ArrayList<NameValuePair>(); for(Map.Entry<String,String> entry:map.entrySet()){ Stringname = entry.getKey(); Stringvalue = entry.getValue(); NameValuePairnvp = new BasicNameValuePair(name, value); parameters.add(nvp); } //实体 UrlEncodedFormEntityentity = new UrlEncodedFormEntity(parameters, "utf-8"); //把实体设置给请求对象 request.setEntity(entity); //执行请求 HttpResponseresponse = client.execute(request); //判断响应码是否为200 if(response.getStatusLine().getStatusCode()== 200){ //获取服务器回送的流 InputStreaminputStream = response.getEntity().getContent(); //返回 success or error Stringcontent = changeStreamToString(inputStream); if("success".equals(content)){ returntrue; }else{ returnfalse; } } returnfalse; }
•(掌握)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{
publicstatic final int SUCCESS_LOAD_DATA = 0; privateImageView iv; privateButton bt_set; privateFile file;
privateHandler mHandler = new Handler(){ publicvoid handleMessage(android.os.Message msg) { switch(msg.what) { caseSUCCESS_LOAD_DATA: Uriuri = (Uri) msg.obj; iv.setImageURI(uri); //图片下载成功 //设置按钮可用 bt_set.setEnabled(true); break;
default: break; } }; };
@Override protectedvoid 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);
}
publicvoid download(View v){ // 从服务器上下载图片 //使用api: Thread 权限 HttpClient Environment //目的:把图片下载到sdcard newThread(new MyTask()).start(); } privateclass MyTask implements Runnable{
//下载图片 @Override publicvoid run() {
Stringpath = "http://10.0.2.2:8080/08web/tokhot4.JPG"; try{ //客户端 HttpClientclient = new DefaultHttpClient(); //请求对象 HttpGetrequest = new HttpGet(path); //执行请求 获取响应对象 HttpResponseresponse = client.execute(request); //判断响应是否成功 if(response.getStatusLine().getStatusCode()== 200){ //获取服务器回送的流 InputStreaminputStream = response.getEntity().getContent();
//把流保存成文件 Stringname = getFileName(path); file= new File(Environment.getExternalStorageDirectory(),name); FileOutputStreamfos = new FileOutputStream(file); byte[]buffer = new byte[1024]; intlen = 0; while((len= inputStream.read(buffer)) != -1){ fos.write(buffer,0, len); } fos.close(); inputStream.close();
//显示图片 Uriuri = Uri.fromFile(file);//获取文件的uri Messagemsg = Message.obtain(mHandler, SUCCESS_LOAD_DATA, uri); msg.sendToTarget();
}else{ alertUser("下载失败"); } }catch (Exception e) { e.printStackTrace(); alertUser("下载失败"); } }
}
publicvoid set(View v){ newThread(){ publicvoid run() { try{ /*//设置墙纸 Drawabledrawable = iv.getDrawable(); //请求问Drawable如何转换成bitmap */ Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); setWallpaper(bitmap);//设置墙纸是一个耗时的操作 开线程 alertUser("设置成"); }catch (Exception e) { e.printStackTrace(); alertUser("设置失败"); } }; }.start();
}
/** * 根据网络路径获取文件名称 * @param path * @return */ privateString getFileName(String path){ returnpath.substring(path.lastIndexOf("/")+1); }
privatevoid alertUser(final String text){ runOnUiThread(newRunnable() {
@Override publicvoid run() { Toast.makeText(getApplicationContext(),text, 0).show(); } }); }
/** * 把Drawable转换成Bitmap * @param drawable * @return */ publicstatic 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 文件的大小 联网获取文件的大小,只需要服务器告诉我文件的大小,不需要文件流 只要响应的头信息:
2 请求服务器指定范围的数据 Http协议他可以指定范围: key:Range value:bytes:start-end
3 把服务返回的数据正确的写入到指定的位置 RandomAccessFile 随机访问文件
•(掌握)android多线程下载获取服务器上文件的大小
在客户创建和服务器大小一样的文件
计算block每条线程的下载量
开启三条线程下载
下载线程
/** * 下载线程的参数: * 下载的资源 path * 每条线程的下载量block * 下载线程的id threadid * 下载文件的存放位置 file * 可以通过:block threadid 计算出开始位置 和结束位置 * */ privateclass DownloadThread extends Thread{ privateString path; privateint block; privateint threadid; privateFile file; privateint start;//开始位置 privateint end;//结束位置
publicDownloadThread(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 publicvoid run() { super.run(); try{ //执行分段下载 HttpClientclient = new DefaultHttpClient(); HttpGet request = new HttpGet(path); //设置下载的范围 request.addHeader("Range","bytes:"+start+"-"+end); HttpResponseresponse = client.execute(request); //分段下载服务器的响应码是:206 if(response.getStatusLine().getStatusCode()== 206){ InputStreaminputStream = response.getEntity().getContent();
RandomAccessFile raf = new RandomAccessFile(file,"rwd"); //跳转到要写入的位置 raf.seek(start);
//把数据写入到文件 byte[]buffer = new byte[1024]; intlen = 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 点击继续下载
你们在敲这个项目的时候,用两个按钮。
•(了解)开源项目多线程断点下载Afinal框架 是一个中国人整合一些国外的框架。 一行搞定所有的事情 Afinal 框架 升级到了Xutils框架 (智能北京)
下载资源
希望大家积极转发、分享,让更多的人轻松学习! 相关链接:
长沙中心--黑马双元课堂JAVA入学辅导班1期火爆开班啦!!! 长沙黑马程序员学习激情无限“吊炸天”
|