Android学习笔记 day05 _ 网络编程2
一、 获取服务器数据时乱码问题解决
乱码原因:
Android客户端在服务器取数据时编码与服务器编码不一样,因此我们要让客户端和服务器 两端的字符集编码保持一致,通常采用UTF-8编码
解决办法:
1. 修改Android客户端编码: 使用URLEncoder.encode(name,"UTF-8")进行url编码: String path = "http://192.168.22.136:8080/web/servlet/LoginServlet?username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8"); 2. 修改服务器编码:
二、 第二种向服务器获取数据方式:HttpClient
GET方式执行过程:
// 1. 创建一个url对象 参数就是网址 String path = "http://192.168.1.102/web/servlet/LoginServlet?username=" + name + "&password=" + pwd; // (1) 初始化HttpClient对象 HttpClient client = new DefaultHttpClient(); // (2) 创建一个get请求 HttpGet get = new HttpGet(path); // (3) 执行一个get请求 HttpResponse response = client.execute(get); // (4) 返回请求状态码 int code = response.getStatusLine().getStatusCode(); if (code == 200) { // 6. 获取服务器给我们返回的数据 InputStream in = response.getEntity().getContent(); // 7. 处理结果 final String content = StreamUtils.readStream(in); // 8. //更新UI界面 showToast(content); }
POST方式执行过程:
// 1. 获取用户填写的用户名和密码 final String name = et_username.getText().toString().trim(); final String pwd = et_password.getText().toString().trim(); // 2. 登录的逻辑 new Thread() { public void run() { try { String path = "http://192.168.1.102/web/servlet/LoginServlet"; // (1) 初始化HttpClient对象 HttpClient client = new DefaultHttpClient(); // (2) 创建一个post请求 HttpPost post = new HttpPost(path); // ☆☆☆ 和get请求不同之处:封装我们请求的实体数据 List<NameValuePair> parameters = new ArrayList<NameValuePair>(); NameValuePair nameValuePair = new BasicNameValuePair( "username", name); NameValuePair pwdValuePair = new BasicNameValuePair( "password", pwd); parameters.add(nameValuePair); parameters.add(pwdValuePair); UrlEncodedFormEntity entity = new UrlEncodedFormEntity( parameters); // (3) 封装请求数据到实体对象中 post.setEntity(entity); // (4) 执行一个post请求 HttpResponse response = client.execute(post); // (5) 返回请求状态码 int code = response.getStatusLine().getStatusCode(); if (code == 200) { // 6. 获取服务器给我们返回的数据 InputStream in = response.getEntity().getContent(); // 7. 处理结果 final String content = StreamUtils.readStream(in); // 8. 更新界面 showToast(content); } } catch (Exception e) { e.printStackTrace(); } }; }.start();
两种提交方式不同之处:
1. 路径不同 2. get把提交的数据放在URL上提交到服务器, post把数据封装在NameValuePair对象中,然后提交到服务器
与HttpURLConnection方式获取服务器数据不同之处:
易用性和灵活性更强
三、 第三种向服务器获取数据方式:Aynchttpclient
Aynchttpclient介绍:
Aynchttpclient是一个第三方的开源项目,可以在Github网站上获取源码,它封装了向服务器获取数据的方法,底层原理使用HttpClient实现
使用方法:
1. 导入Aynchttpclient源码到工程中 2. get方式: // (1) 初始化AsyncHttpClient对象 AsyncHttpClient client = new AsyncHttpClient(); // (2) 执行get请求 client.get(path, new AsyncHttpResponseHandler() {}; 3. post方式: // (1)初始化AsyncHttpClient对象 AsyncHttpClient client = new AsyncHttpClient(); // (2) 封装参数数据 RequestParams params = new RequestParams(); params.put("username", name); params.put("password", pwd); // (3) 执行get请求 client.post(path, new AsyncHttpResponseHandler() {}
- 使用Aynchttpclient上传文件
四、 Java实现多线程下载
多线程下载实现原理:
原理:使用多线程下载相当于让更多的线程去竞争CPU资源,相对单线程下载服务器将分配给你更多的CPU资源,从而实现加速下载
实现过程:
1. 使用HttpURLConnection获取服务器要下载文件的大小 // 1. 创建一个url对象 参数就是网址 URL url = new URL(path); // 2. 获取HttpURLConnection 链接对象 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 3. 设置参数 发送get请求 conn.setRequestMethod("GET"); // 必须大写 // 4. 设置链接网络的超时时间 conn.setConnectTimeout(5000); // 5. 获取服务器返回的状态码 int code = conn.getResponseCode(); if (code == 200) { // 6. 获取文件的大小 int length = conn.getContentLength(); 2. 在客户端创建一个与服务器端大小一样的空白文件 RandomAccessFile raf = new RandomAccessFile("temp.exe", "rw"); raf.setLength(length); 3. 计算每个子线程下载的数据块大小和下载起始位置、结束位置 // 二、☆☆☆ 算出每个线程下载的大小 int threadSize = length / threadCount; // 三、☆☆☆ 计算每个线程下载的开始位置和结束位置 for (int i = 0; i < threadCount; i++) { int startIndex = i * threadSize; int endIndex = (i + 1) * threadSize - 1; if (i == threadCount - 1) { // 最后一个线程 endIndex = length - 1; } } 4. 创建子线程开始下载数据 // 三、☆☆☆ 开启多个线程,去真正的下载文件 DownloadThread thread = new DownloadThread(path, startIndex, endIndex, i); thread.start();
五、 Java实现断点续传下载
实现过程:
实时记录线程下载的位置,并保存到文件中
// 计算当前线程下载的位置并保存到文件中 total += len; int currentThreadPosition = total + startIndex; RandomAccessFile ras = new RandomAccessFile(threadId + ".txt", "rwd"); ras.write(String.valueOf(currentThreadPosition) .getBytes()); ras.close();
读取记录上一次下载的位置的文件,继续下载
File file = new File(threadId + ".txt"); // 判断是否有上次下载未完成的文件,若有则继续下载 if (file.exists() && file.length() > 0) { // 读取文件中存储的上次下载到的流的位置 FileInputStream fis = new FileInputStream(file); BufferedReader br = new BufferedReader( new InputStreamReader(fis)); String lastPosition = br.readLine(); // 第二次下载的时候,按照这个位置继续下载 // ☆☆☆ 告诉服务器,每个线程下载的开始位置和结束位置 conn.setRequestProperty("Range", "bytes=" + lastPosition + "-" + endIndex); startIndex = Integer.parseInt(lastPosition); fis.close();
六、 使用开源项目XUtils实现多线程下载
XUtils简介:
开源的一个框架,包含了很多实用的Android工具,主要有四大模块功能: - DbUtils模块 - ViewUtils模块 - HttpUtils模块 - BitmapUtils模块 其中,HttpUtils模块提供了文件多线程断点续传下载功能
使用方法:
1. 导入XUtils jar包或者在src目录下导入XUtils源码 2. 创建HttpUtils实例对象: HttpUtils http = new HttpUtils(); 3. 调用HttpUtils对象的download方法: download(String url, String target, boolean autoResume, RequestCallBack<File> callback)