Android基礎-05

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("開始下載...");
        }
    });

}
}
資料下載
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章