Android基础-05

刘野
2023-12-01

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

}
}
资料下载
 类似资料: