01_使用POST方式提交数据时的中文乱码解决方法(重点)
解决办法:使用客户端和服务器两边的字符集编码保持一致。 UTF-8,02_使用GET方式提交数据的中文乱码的解决方法
使用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");
03_使用httpclient提交数据(重点)
apache httpClient 轻量级的浏览器* 使用GET方式数据步骤:
1、创建一个浏览器: 2、输入一个网址: 3、敲回车 模块代码: package com.itheima.qqlogin; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import com.itheima.htmlview.utils.StreamTools; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private EditText et_name; private EditText et_pwd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_name = (EditText) findViewById(R.id.et_name); et_pwd = (EditText) findViewById(R.id.et_pwd); } public void login(View view){ final String name = et_qq.getText().toString().trim(); final String pwd = et_pwd.getText().toString().trim(); if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)){ Toast.makeText(this, "qq和密码不能空", 0).show(); return; }else{ new Thread(){ public void run() { try { String path = "http://192.168.22.136:8080/web/servlet/LoginServlet?username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8"); // // 1、创建一个浏览器: HttpClient client = new DefaultHttpClient(); // 2、输入一个网址: HttpGet httpGet = new HttpGet(path); // // 3、敲回车 HttpResponse response = client.execute(httpGet); //获取服务器端返回的响应码(状态码) int code = response.getStatusLine().getStatusCode(); // int code = conn.getResponseCode(); if(code == 200){ // (2)解析服务器返回的二进制数据,解析成一个字符串 // InputStream is = conn.getInputStream(); //获取服务器返回的二进制数据流 InputStream is = response.getEntity().getContent(); String result = StreamTools.readStream(is); System.out.println("---------"+ result); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } } }
使用post方式向服务器端提交数据
1、创建一个浏览器:2、输入一个网址:
3、敲回车
模版代码:
package com.itheima.qqlogin; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.Toast; import com.itheima.htmlview.utils.StreamTools; public class MainActivity extends Activity { private EditText et_qq; private EditText et_pwd; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { String result = (String) msg.obj; Toast.makeText(MainActivity.this, result, 0).show(); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_pwd = (EditText) findViewById(R.id.et_pwd); } public void login(View view){ final String name = et_qq.getText().toString().trim(); final String pwd = et_pwd.getText().toString().trim(); if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)){ Toast.makeText(this, "qq和密码不能空", 0).show(); return; }else{ new Thread(){ public void run() { try { String path = "http://192.168.22.136:8080/web/servlet/LoginServlet"; // String data = "username="+name+"&password="+pwd; String data = "username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8"); // 1、创建一个浏览器: HttpClient client = new DefaultHttpClient(); // 2、输入一个网址: HttpPost httpPost = new HttpPost(path); List<BasicNameValuePair> parameters = new ArrayList<BasicNameValuePair>(); BasicNameValuePair p1 = new BasicNameValuePair("username", name); BasicNameValuePair p2 = new BasicNameValuePair("password", pwd); parameters.add(p1); parameters.add(p2); //默认使用iso-8859-1编码,需要指定UTF-8 UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters,"UTF-8"); // // 3、敲回车 //设置提交的数据 httpPost.setEntity(entity); HttpResponse response = client.execute(httpPost); // 2、服务器返回数据 // (1)判断状态码:200 ok,404 没有找到资源、503、509 服务器端错误 int code = response.getStatusLine().getStatusCode(); // int code = conn.getResponseCode(); if(code == 200){ // (2)解析服务器返回的二进制数据,解析成一个字符串 InputStream is = response.getEntity().getContent(); String result = StreamTools.readStream(is); System.out.println("---------"+ result); Message msg = Message.obtain(); msg.obj = result; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } } }
04_使用Aynchttpclient向服务器端提交数据(重点)
1、创建一个浏览器:2、输入一个网址:
3、敲回车
package com.itheima.qqlogin; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import org.apache.http.Header; import com.itheima.htmlview.utils.StreamTools; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private EditText et_name; private EditText et_name; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_pwd = (EditText) findViewById(R.id.et_pwd); } public void login(View view){ final String name = et_qq.getText().toString().trim(); final String pwd = et_pwd.getText().toString().trim(); if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)){ Toast.makeText(this, "qq和密码不能空", 0).show(); return; }else{ try { String path = "http://192.168.22.136:8080/web/servlet/LoginServlet?username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8"); //1、创建一个浏览器: AsyncHttpClient client = new AsyncHttpClient(); // 1、输入网址,调用get方式向服务器发送请求: client.get(path, new AsyncHttpResponseHandler() { /* * 请求成功,服务器端正常响应 响应码200 * statusCode 响应码200ok,404没有找到资源,503服务器内部错误, Header[] headers 响应头信息, byte[] responseBody 服务器返回的数据 */ @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } /* * 请求成功,服务器端正常响应 响应码200 * int statusCode, Header[] headers, byte[] responseBody, Throwable error * statusCode 响应码200ok,404没有找到资源,503服务器内部错误, Header[] headers 响应头信息, byte[] responseBody 服务器返回的数据 * Throwable error 服务器端返回的异常 */ @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable arg3) { Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } }); } catch (Exception e) { e.printStackTrace(); } }; } }
使用POST方式向服务器端提交数据
package com.itheima.qqlogin; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import org.apache.http.Header; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.Toast; import com.itheima.htmlview.utils.StreamTools; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.RequestParams; public class MainActivity extends Activity { private EditText et_qq; private EditText et_pwd; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { String result = (String) msg.obj; Toast.makeText(MainActivity.this, result, 0).show(); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_qq = (EditText) findViewById(R.id.et_qq); et_pwd = (EditText) findViewById(R.id.et_pwd); } public void login(View view){ final String name = et_qq.getText().toString().trim(); final String pwd = et_pwd.getText().toString().trim(); if(TextUtils.isEmpty(name) || TextUtils.isEmpty(pwd)){ Toast.makeText(this, "qq和密码不能空", 0).show(); return; }else{ try { String path = "http://192.168.22.136:8080/web/servlet/LoginServlet"; // String data = "username="+name+"&password="+pwd; // String data = "username="+URLEncoder.encode(name,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8"); // 1、创建一个浏览器: AsyncHttpClient client = new AsyncHttpClient(); // 2、输入一个网址,敲回车: RequestParams params = new RequestParams(); params.put("username", name); params.put("password", pwd); client.post(path, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable e) { Toast.makeText(MainActivity.this, new String("服务器端返回数据失败"), 0).show(); } }); } catch (Exception e) { e.printStackTrace(); } } } }
05_多线程下载的原理
线程可以理解为下载的通道,一个线程就是一个文件的下载通道, 多线程也就是同时开起好几个下载通道.当服务器提供下载服务时, 使用下载者是共享带宽的,在优先级相同的情况下, 总服务器会对总下载线程进行平均分配。 不难理解, 如果你线程多的话,那下载的越快。现流行的下载软件都支持多线程。
06_javase实现多线程
步骤:1、在客户端创建一个与服务器端大小一样的空白文件
2、设置子线程的个数
3、计算每个子线程下载的数据块大小和下载起始位置、结束位置
4、创建子线程开始下载数据
5、得到每个子线程都下载完成的标记
代码:
MultiThreadDownLoader.java:
import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MultiThreadDownLoader { //2、使用的子线程的个数 private static int threadCount =3; /** * @param args */ public static void main(String[] args) { try { String path = "http://192.168.22.136:8080/sogou.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); int code = conn.getResponseCode(); if(code == 200){ int length = conn.getContentLength(); //1、在客户端创建一个与服务端文件一样大小的文件 RandomAccessFile file = new RandomAccessFile("temp.exe", "rw"); file.setLength(length); //3、每个子线程下载数据块 ,下载的起始位置和结束位置 int blockSize = length/threadCount; // threadId * blockSize ---- (threadId+1)* blockSize -1 for(int threadId =0; threadId < threadCount; threadId++){ //下载的起始位置和结束位置 int startIndex = threadId * blockSize; int endIndex = 0; if(threadId != (threadCount -1)){ endIndex = (threadId + 1) * blockSize - 1; }else{ endIndex = length-1; } //开启子线程下载数据 new ThreadDownLoader(path, startIndex, endIndex, threadId, threadCount).start(); } }else{ //抛出异常 } } catch (Exception e) { e.printStackTrace(); } } }
ThreadDownLoader.java:
import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class ThreadDownLoader extends Thread { private String path; private int startIndex; private int endIndex; private int threadId; private int threadCount; //正在运行的线程个数 private static int runningThreadCount = 3; ThreadDownLoader(String path,int startIndex,int endIndex,int threadId,int threadCount){ this.path = path; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; this.threadCount = threadCount; } @Override public void run() { downLoad(path,startIndex,endIndex,threadId,threadCount); } public void downLoad(String path,int startIndex,int endIndex,int threadId,int threadCount) { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); //设置子线程请求数据的范围 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); int code = conn.getResponseCode(); if(code == 206){//请求部分数据 InputStream is = conn.getInputStream(); RandomAccessFile file = new RandomAccessFile("temp.exe","rw"); //指定从哪个位置开始写数据 file.seek(startIndex); byte[] buffer = new byte[1024]; int len = -1; while((len = is.read(buffer)) != -1){ file.write(buffer, 0, len); } file.close(); System.out.println("线程"+threadId+"下载完成..............."); synchronized (ThreadDownLoader.this) { runningThreadCount--; if(runningThreadCount == 0){ System.out.println("文件下载完成..............."); } } } } catch (Exception e) { System.out.println("线程"+threadId+"下载失败..............."); e.printStackTrace(); } } }
07_断点续传下载
1、实时记录线程下载的位置;2、接上一次下载的位置继续下载;
代码:
import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.nio.channels.ReadableByteChannel; public class ThreadDownLoader extends Thread { private String path; private int startIndex; private int endIndex; private int threadId; private int threadCount; //正在运行的线程个数 private static int runningThreadCount = 3; ThreadDownLoader(String path,int startIndex,int endIndex,int threadId,int threadCount){ this.path = path; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; this.threadCount = threadCount; } @Override public void run() { downLoad(path,startIndex,endIndex,threadId,threadCount); } public void downLoad(String path,int startIndex,int endIndex,int threadId,int threadCount) { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); //获取上一次下载的位置,接着下载 File threadFile = new File(threadId+".txt"); if(threadFile.exists() && threadFile.length() > 0){ FileReader fr = new FileReader(threadFile); BufferedReader br = new BufferedReader(fr); String position = br.readLine(); //设置子线程请求数据的范围 conn.setRequestProperty("Range", "bytes="+position+"-"+endIndex); startIndex = Integer.valueOf(position); }else{ //设置子线程请求数据的范围 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); } int code = conn.getResponseCode(); if(code == 206){//请求部分数据 InputStream is = conn.getInputStream(); RandomAccessFile file = new RandomAccessFile("temp.exe","rw"); //指定从哪个位置开始写数据 file.seek(startIndex); byte[] buffer = new byte[1024*1024]; int len = -1; int total = 0; while((len = is.read(buffer)) != -1){ file.write(buffer, 0, len); total = total + len; int currentPosition = startIndex + total; //能够即时的把数据写到数据 RandomAccessFile f = new RandomAccessFile(threadId+".txt", "rwd"); f.write((currentPosition+"").getBytes()); f.close(); } file.close(); System.out.println("线程"+threadId+"下载完成..............."); synchronized (ThreadDownLoader.this) { runningThreadCount--; if(runningThreadCount == 0){ System.out.println("文件下载完成..............."); } } } } catch (Exception e) { System.out.println("线程"+threadId+"下载失败..............."); e.printStackTrace(); } } }
08_多线程下载移植到Android项目上(重点)
1、设置布局文件:
<LinearLayout 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" android:orientation="vertical" tools:context=".MainActivity" > <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入下载的文件网络地址" android:id="@+id/et_path" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="开启几个子线程加速下载" android:text="3" android:id="@+id/et_threadCount" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="下载" android:onClick="downLoad" /> </LinearLayout>
2、修改代码:
MainActivity.java:package com.itheima.multithreaddownload; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { private EditText et_path; private EditText et_threadCount; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_path = (EditText) findViewById(R.id.et_path); et_threadCount = (EditText) findViewById(R.id.et_threadCount); } public void downLoad(View view){ final String path = et_path.getText().toString().trim(); String threadCountStr = et_threadCount.getText().toString().trim(); if(TextUtils.isEmpty(path) || TextUtils.isEmpty(threadCountStr)){ Toast.makeText(this, "下载地址或线程个数不能为空", 0).show(); return; }else{ // final int threadCount = Integer.valueOf(threadCountStr); new Thread(){ public void run() { try { // String path = "http://192.168.22.136:8080/sogou.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(3000); int code = conn.getResponseCode(); if(code == 200){ int length = conn.getContentLength(); //1、在客户端创建一个与服务端文件一样大小的文件 RandomAccessFile file = new RandomAccessFile(Environment.getExternalStorageDirectory()+"/temp.exe", "rw"); file.setLength(length); //3、每个子线程下载数据块 ,下载的起始位置和结束位置 int blockSize = length/threadCount; // threadId * blockSize ---- (threadId+1)* blockSize -1 for(int threadId =0; threadId < threadCount; threadId++){ //下载的起始位置和结束位置 int startIndex = threadId * blockSize; int endIndex = 0; if(threadId != (threadCount -1)){ endIndex = (threadId + 1) * blockSize - 1; }else{ endIndex = length-1; } //开启子线程下载数据 new ThreadDownLoader(path, startIndex, endIndex, threadId, threadCount).start(); } }else{ //抛出异常 } } catch (Exception e) { e.printStackTrace(); } }; }.start(); } } }
##09_使用xutils实现多线程下载(重点)
1. 导入xutils包 2. 初始化httputils对象 HttpUtils http = new HttpUtils(); /** * 2 进行下载 * url 下载的路径 * target 存放目标地址 * autoResume 是否支持断点续传下载 */ http.download(path, "/mnt/sdcard/feiq.exe", true, new RequestCallBack<File>() { //下载成功的回调 @Override public void onSuccess(ResponseInfo<File> responseInfo) { Toast.makeText(getApplicationContext(), "下载成功", 0).show(); } //下载失败的回调 @Override public void onFailure(HttpException error, String msg) { } //当前进度 @Override public void onLoading(long total, long current, boolean isUploading) { pb.setMax((int) total); //设置进度条的最大值 pb.setProgress((int) current); super.onLoading(total, current, isUploading); } });