Android应用程序中默认是的字符集编码是UTF-8。
java.io.IOException: exceeded content-length limit of 29 bytes
在代码中对中文进行URL编码:
String data = "username="+URLEncoder.encode(username,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8");
解决办法:保持服务器端和客户端的字符集编码一致。
HttpClient apache下面的子项目。轻量级的浏览器。
步骤:
1、创建一个浏览器:
2、输入网址:
3、敲回车,发送请求:
package com.itheima.qqloginbyget;
import java.io.InputStream;
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 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;
public class MainActivity extends Activity {
protected static final int SUCCESS = 0;
protected static final int FAILED = 1;
private EditText et_username;
private EditText et_pwd;
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case SUCCESS:
String result = (String) msg.obj;
Toast.makeText(MainActivity.this, result, 0).show();
break;
case FAILED:
Toast.makeText(MainActivity.this, "网络异常,获取数据失败", 0).show();
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) findViewById(R.id.et_username);
et_pwd = (EditText) findViewById(R.id.et_pwd);
}
public void login(View view){
final String username = et_username.getText().toString().trim();
final String pwd = et_pwd.getText().toString().trim();
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(pwd) ){
Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
return;
}else{
//访问网络,提交数据给服务器端
new Thread(){
public void run() {
// 访问网络,从网络上获取图片的数据,并且现在imageview
try {
String path="http://192.168.1.254:8080/web/servlet/LoginServlet";
// 1、创建URL对象,打开一个HTTP类型的连接:
String data = "?username="+URLEncoder.encode(username, "UTF-8")+"&password="+URLEncoder.encode(pwd, "UTF-8");
// 1、创建一个浏览器:
HttpClient client = new DefaultHttpClient();
// 2、输入网址:
HttpGet httpGet = new HttpGet(path + data);
// 3、敲回车,发送请求:
HttpResponse response = client.execute(httpGet);
//得到响应码(状态吗)
int code = response.getStatusLine().getStatusCode();
if(200 == code){
//得到服务器端返回的响应数据
InputStream is = response.getEntity().getContent();
// 4、把二进制流的响应数据转换成需要的数据类型:
String result = StreamTools.readStreamToStr(is);
Message msg = Message.obtain();
//定义一个消息码,用来区分消息从什么地方发送的
msg.what = SUCCESS;
msg.obj = result;
handler.sendMessage(msg);
}
} catch (Exception e) {
Message msg = Message.obtain();
//定义一个消息码,用来区分消息从什么地方发送的
msg.what = FAILED;
msg.obj = "网络异常,获取数据失败";
handler.sendMessage(msg);
e.printStackTrace();
}
};
}.start();
}
}
}
package com.itheima.qqloginbyget;
import java.io.InputStream;
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;
public class MainActivity extends Activity {
protected static final int SUCCESS = 0;
protected static final int FAILED = 1;
private EditText et_username;
private EditText et_pwd;
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case SUCCESS:
String result = (String) msg.obj;
Toast.makeText(MainActivity.this, result, 0).show();
break;
case FAILED:
Toast.makeText(MainActivity.this, "网络异常,获取数据失败", 0).show();
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) findViewById(R.id.et_username);
et_pwd = (EditText) findViewById(R.id.et_pwd);
}
public void login(View view){
final String username = et_username.getText().toString().trim();
final String pwd = et_pwd.getText().toString().trim();
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(pwd) ){
Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
return;
}else{
//访问网络,提交数据给服务器端
new Thread(){
public void run() {
// 访问网络,从网络上获取图片的数据,并且现在imageview
try {
String path="http://192.168.1.254:8080/web/servlet/LoginServlet";
// 1、创建URL对象,打开一个HTTP类型的连接:
String data = "username="+URLEncoder.encode(username,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8");
// 1、创建一个浏览器:
HttpClient client = new DefaultHttpClient();
// 2、输入网址:
HttpPost httpPost = new HttpPost(path);
//封装需要提交的数据
List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
BasicNameValuePair pair1 = new BasicNameValuePair("username", username);
BasicNameValuePair pair2 = new BasicNameValuePair("password", pwd);
list.add(pair1);
list.add(pair2);
//把需要提交的数据封装到form实体中
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
//把数据实体放到post对象
httpPost.setEntity(entity);
// 3、敲回车,发送请求:
HttpResponse response = client.execute(httpPost);
int code = response.getStatusLine().getStatusCode();
if(200 == code){
InputStream is = response.getEntity().getContent();
// 4、把二进制流的响应数据转换成需要的数据类型:
String result = StreamTools.readStreamToStr(is);
Message msg = Message.obtain();
//定义一个消息码,用来区分消息从什么地方发送的
msg.what = SUCCESS;
msg.obj = result;
handler.sendMessage(msg);
}
} catch (Exception e) {
Message msg = Message.obtain();
//定义一个消息码,用来区分消息从什么地方发送的
msg.what = FAILED;
msg.obj = "网络异常,获取数据失败";
handler.sendMessage(msg);
e.printStackTrace();
}
};
}.start();
}
}
}
原理:
内部使用子线程访问访问,并对提交的数据进行了URL编码;
代码:
package com.itheima.qqloginbyget;
import java.io.InputStream;
import java.net.URLEncoder;
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.impl.client.DefaultHttpClient;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
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;
public class MainActivity extends Activity {
protected static final int SUCCESS = 0;
protected static final int FAILED = 1;
private EditText et_username;
private EditText et_pwd;
private Handler handler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case SUCCESS:
String result = (String) msg.obj;
Toast.makeText(MainActivity.this, result, 0).show();
break;
case FAILED:
Toast.makeText(MainActivity.this, "网络异常,获取数据失败", 0).show();
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_username = (EditText) findViewById(R.id.et_username);
et_pwd = (EditText) findViewById(R.id.et_pwd);
}
public void login(View view){
final String username = et_username.getText().toString().trim();
final String pwd = et_pwd.getText().toString().trim();
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(pwd) ){
Toast.makeText(this, "qq号码或者密码不能为空", 0).show();
return;
}else{
String path="http://192.168.1.254:8080/web/servlet/LoginServlet";
String data = "?username="+username+"&password="+pwd;
AsyncHttpClient client = new AsyncHttpClient();
client.get(path + data, new AsyncHttpResponseHandler() {
//当前请求处理成功时调用这个方法
//statusCode 状态码
//headers 响应头
//responseBody 响应数据
@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 error) {
Toast.makeText(MainActivity.this,"网络异常,请检查网络", 0).show();
}
});
}
}
}
使用POST方式发送请求
String path="http://192.168.1.254:8080/web/servlet/LoginServlet";
// 1、创建URL对象,打开一个HTTP类型的连接:
//String data = "username="+URLEncoder.encode(username,"UTF-8")+"&password="+URLEncoder.encode(pwd,"UTF-8");
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("username", username);
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 error) {
Toast.makeText(MainActivity.this, "网络异常,情检查网络", 0).show();
}
});
代码:
//根据用户输入的文件路径得到文件对象
String filePath = et_path.getText().toString().trim();
File file = new File(filePath);
String path = "http://192.168.1.254:8080/web/servlet/UploadServlet";
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
//传递文件对象给服务器端
params.put("file", file);
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 error) {
Toast.makeText(MainActivity.this, "网络异常", 0).show();
}
});
多线程下载的原理或步骤:
1、在本地创建一个服务器端一模一样大小的空文件:
大小:content-length;
RandomAccessFile setLength();
2、设置使用几个子线程去下载服务器上的文件:
在应用程序中设置变量代表子线程的个数;
3、每个子线程下载的数据块的大小:
length/threaCount=blocksize;
4、计算每个子线程下载开始位置和结束位置:
开始位置:threadId * blocksize; 结束位置:(threadId+1) * blocksize -1;
最后一个子线程下载结束位置: length-1;
5、创建子线程,下载数据:
设置每个子线程下载数据的范围:Range:bytes=0-3
6、知道在什么时候文件下载完成,所有的子线程都下载完毕:
在程序中设置变量代表正在运行的线程的个数,当每个子线程下载完毕都去减1,当变量为0时表示所有的子线程都结束了;
根据以上6个步骤实现代码:
MultiThreadDownLoader.java:
package com.itheima.multithread;
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.1.254:8080/sogou.exe";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(3000);
int code = conn.getResponseCode();
if (code == 200) {
// 1、在本地创建一个服务器端一模一样大小的空文件
int length = conn.getContentLength();
RandomAccessFile raf = new RandomAccessFile("temp.exe", "rw");
raf.setLength(length);
// 3、每个子线程下载的数据块的大小
int blockSize = length / threadCount;
for (int threadId = 0; threadId < threadCount; threadId++) {
// 4、计算每个子线程下载开始位置和结束位置
int startIndex = threadId * blockSize;
int ednIndex = (threadId+1) * blockSize - 1;
//最后一个子线程下载的结束位置
if(threadId == (threadCount-1)){
ednIndex = length - 1;
}
//创建子线程开始下载数据
new DownLoadChildThread(path,threadId,startIndex,ednIndex).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
DownLoadChildThread.java:
package com.itheima.multithread;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
public class DownLoadChildThread extends Thread {
private String url;
private int threadId;
private int startIndex;
private int ednIndex;
//设置正在运行的线程的个数
private static int runningThreadCount = 3;
public DownLoadChildThread(String url, int threadId, int startIndex,
int ednIndex) {
this.url = url;
this.threadId = threadId;
this.startIndex = startIndex;
this.ednIndex = ednIndex;
}
@Override
public void run() {
try {
//5、创建子线程,下载数据:
URL url = new URL("http://192.168.1.254:8080/sogou.exe");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(3000);
//设置请求的数据范围
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+ednIndex);
System.out.println("线程"+threadId+"下载的范围:"+startIndex+"-"+ednIndex);
//请求部分数据成功,响应码为206
int code = conn.getResponseCode();
if(code == 206){
InputStream is = conn.getInputStream();
RandomAccessFile raf = new RandomAccessFile("temp.exe", "rw");
//从指定的位置开始写数据
raf.seek(startIndex);
byte[] buffer = new byte[1024];
int len = -1;
while((len = is.read(buffer)) != -1){
raf.write(buffer, 0, len);
}
is.close();
raf.close();
System.out.println("线程"+threadId+"下载完成........................");
//每个子线程下载完成时都去减1
synchronized (DownLoadChildThread.class) {
runningThreadCount--;
if(runningThreadCount == 0){
System.out.println("文件下载完成...........................");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码:
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;
// 2、设置线程的个数
private static int threadCount = 3;
@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)){
Toast.makeText(this, "请输入文件的下载地址", 0).show();
return;
}
if(!TextUtils.isEmpty(threadCountStr)){
threadCount = Integer.parseInt(threadCountStr);
}
new Thread(){
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(3000);
int code = conn.getResponseCode();
if (code == 200) {
// 1、在本地创建一个服务器端一模一样大小的空文件
int length = conn.getContentLength();
RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory()+"/temp.exe", "rw");
raf.setLength(length);
// 3、每个子线程下载的数据块的大小
int blockSize = length / threadCount;
for (int threadId = 0; threadId < threadCount; threadId++) {
// 4、计算每个子线程下载开始位置和结束位置
int startIndex = threadId * blockSize;
int ednIndex = (threadId+1) * blockSize - 1;
//最后一个子线程下载的结束位置
if(threadId == (threadCount-1)){
ednIndex = length - 1;
}
//创建子线程开始下载数据
new DownLoadChildThread(path,threadId,startIndex,ednIndex,threadCount).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
}
DownLoadChildThread.java:
package com.itheima.multithreaddownload;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.Environment;
public class DownLoadChildThread extends Thread {
private String path;
private int threadId;
private int startIndex;
private int ednIndex;
//设置正在运行的线程的个数
private int runningThreadCount;
public DownLoadChildThread(String path, int threadId, int startIndex,
int ednIndex,int runningThreadCount) {
this.path = path;
this.threadId = threadId;
this.startIndex = startIndex;
this.ednIndex = ednIndex;
this.runningThreadCount = runningThreadCount;
}
@Override
public void run() {
try {
//5、创建子线程,下载数据:
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(3000);
//设置请求的数据范围
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+ednIndex);
System.out.println("线程"+threadId+"下载的范围:"+startIndex+"-"+ednIndex);
//请求部分数据成功,响应码为206
int code = conn.getResponseCode();
if(code == 206){
InputStream is = conn.getInputStream();
RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory()+"/temp.exe", "rw");
//从指定的位置开始写数据
raf.seek(startIndex);
byte[] buffer = new byte[1024];
int len = -1;
while((len = is.read(buffer)) != -1){
raf.write(buffer, 0, len);
}
is.close();
raf.close();
System.out.println("线程"+threadId+"下载完成........................");
//每个子线程下载完成时都去减1
synchronized (DownLoadChildThread.class) {
runningThreadCount--;
if(runningThreadCount == 0){
System.out.println("文件下载完成...........................");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
XUtils
引入xUtils-2.6.10.jar文件;
代码:
package com.itheima.xutils;
import java.io.File;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
public class MainActivity extends Activity {
private TextView tv_start;
private TextView tv_progress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_start = (TextView) findViewById(R.id.tv_start);
tv_progress = (TextView) findViewById(R.id.tv_progress);
}
public void download(View view){
HttpUtils http = new HttpUtils();
String path = "http://192.168.1.254:8080/11.exe";
http.download(path, Environment.getExternalStorageDirectory()+"/11.exe", true, new RequestCallBack<File>() {
@Override
public void onSuccess(ResponseInfo<File> response) {
Toast.makeText(MainActivity.this, "文件下载,保存在"+response.result.getPath(), 0).show();
}
@Override
public void onFailure(HttpException e, String str) {
Toast.makeText(MainActivity.this, "文件失败", 0).show();
}
@Override
public void onLoading(long total, long current, boolean isUploading) {
super.onLoading(total, current, isUploading);
tv_progress.setText(current+"/"+total);
}
@Override
public void onStart() {
super.onStart();
tv_start.setText("开始下载...");
}
});
}
}
资料下载