Android基礎-05 網絡編程2
01_post方式提交數據的中文亂碼解決(重點)
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");
02_get提交數據亂碼的解決(重點):
解決辦法:保持服務器端和客戶端的字符集編碼一致。
03_使用HttpClient向服務器端提交數據(重點)
HttpClient apache下面的子項目。輕量級的瀏覽器。
步驟:
1、創建一個瀏覽器:
2、輸入網址:
3、敲回車,發送請求:
1、使用GET方式發送請求:
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();
}
}
}
2、使用POST方式發送請求:
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();
}
}
}
04使用開源項目Asynchttpclient的GETPOST訪問網絡(重點)
原理:
內部使用子線程訪問訪問,並對提交的數據進行了URL編碼;
代碼:
1、使用GET方式發送請求:
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();
}
});
05_上傳文件(重點)
代碼:
//根據用戶輸入的文件路徑得到文件對象
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();
}
});
06_多線程加速下載的原理
07_多線程下載的原理
多線程下載的原理或步驟:
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時表示所有的子線程都結束了;
08_javase多線程下載的邏輯
根據以上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();
}
}
}
09_多線程下載的Android移植
代碼:
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();
}
}
}
10_開目實現多線程下載(重點)
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("開始下載...");
}
});
}
}
資料下載