Android中的网络技术基础用法

Posted 曹半斤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中的网络技术基础用法相关的知识,希望对你有一定的参考价值。

有的时候用多了android的一些开源框架用多了,就会把最基础的一些东西给忘了,今天来重温一下Android的网络基础。包括这个Http协议的网络请求,JSON解析。

使用HTTP协议访问网络

在 Android上发送 HTTP 请求的方式一般有两种,HttpURLConnection 和 HttpClient,先来看一下 HttpURLConnection 的用法。首先需要获取到 HttpURLConnection 的实例,一般只需 new出一个 URL 对象,并传入目标的网络地址,然后调用一下 openConnection()方法即可,下面来看一下HttpURLConnection 一个GET请求方式的例子:

public class HttpActivity extends Activity implements OnClickListener{
        private TextView data;
        private Button getdata;
        private static final int SHOWTEXT=1; 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_http);
            initview();
        }

        private void initview(){
            data=(TextView) findViewById(R.id.text);
            getdata=(Button) findViewById(R.id.getdata);
            getdata.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.getdata:
                getdata();
                break;

            default:
                break;
            }
        }
        Handler handler=new Handler(){
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case SHOWTEXT:
                    //将msg.obj设置进来
                    data.setText(msg.obj.toString());
                    break;

                default:
                    break;
                }
            };
        };

        private void getdata() {
            //开启子线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    HttpURLConnection connection=null;
                    try {
                        URL url=new URL("https://www.baidu.com/");
                        //利用url对象来获取HttpURLConnection的实例调用openConnection
                        connection=(HttpURLConnection) url.openConnection();
                        //读取超时的毫秒数
                        connection.setReadTimeout(8000);
                        //设置请求方式
                        connection.setRequestMethod("GET");
                        //连接响应时间
                        connection.setConnectTimeout(8000);
                        //获取到请求回来的输入流
                        InputStream inputStream=connection.getInputStream();
                        //对获取到的输入流进行读取
                        BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
                        StringBuilder builder=new StringBuilder();
                        String line;
                        while ((line=reader.readLine())!=null) {
                            builder.append(line);
                        }
                        // 将服务器返回的结果存放到Message中
                        Message message=new Message();
                        message.what=SHOWTEXT;
                        //将返回结果放到message.obj当中
                        message.obj=builder.toString();
                        handler.sendMessage(message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        if(connection!=null){
                            connection.disconnect();//将http连接关闭
                        }
                    }
                }
            }).start();
        }
}

添加网络权限后运行程序:

这里写图片描述

就可以成功获取到百度的一些html代码.只是通常情况下浏览器都会将这些代码解析成漂亮的网页后再展示出来。

如果是想要提交数据给服务器的话我们只需将GET 改成POST,并在获取输入流之前把要提交的数据写出即可注意每条数据都要以键值对的形式存在,数据与数据之间用&符号隔开,比如说我们想要向服务器提交用户名和密码,就可以这样写:

connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");

使用 HttpClient

HttpClient是Apache提供的HTTP网络访问接口, 从一开始的时候就被引入到了AndroidAPI中。它可以成和 HttpURLConnection 几乎一模一样的效果,但两者之间的用法却有较大的差别,那么我们自然要看一下 HttpClient是如何使用的了。
注意

设置android SDK的编译版本为23时,且使用了httpClient相关类的库项目:如xutis3.0以下等等,会出现有一些类找不到的错误。
android6.0SDK中删除HttpClient的相关类的解决方法(android 6.0已经不再支持HttpClient):

1.eclipse:
libs中加入
org.apache.http.legacy.jar
上面的jar包在:**\\android-sdk-windows\\platforms\\android-23\\optional下(需要下载android 6.0的SDK)

2.android studio:
在相应的module下的build.gradle中加入:
android {
useLibrary ‘org.apache.http.legacy’
}
注意放置的位置:是在android {}中

下面来看下HttpClient的一个GET请求例子:

public class HttpClientActivity extends Activity{
        private TextView data;
        private Button getdata;
        private static final int SHOW_RESPONSE=1;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_http);
            data=(TextView) findViewById(R.id.text);
            getdata=(Button) findViewById(R.id.getdata);
            getdata.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    getdata();
                }


            });
        }
        Handler handler=new Handler(){
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                case SHOW_RESPONSE:
                    data.setText(msg.obj.toString());
                    break;

                default:
                    break;
                }
            };
        };
        private void getdata() {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    HttpClient client=new DefaultHttpClient();
                    HttpGet get=new HttpGet("https://www.baidu.com/");
                    try {
                        HttpResponse response=client.execute(get);
                        if(response.getStatusLine().getStatusCode()==200){
                            HttpEntity entity=response.getEntity();
                            String respon=EntityUtils.toString(entity,"utf-8");
                            Message message = new Message();
                            message.what = SHOW_RESPONSE;
                            // 将服务器返回的结果存放到Message中
                            message.obj = respon.toString();
                            handler.sendMessage(message);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
}

HttpClient的POST方法:
Post方法稍微会比GET方法复杂一点

HttpPost httpPost = new HttpPost("http://www.baidu.com");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "admin"));
params.add(new BasicNameValuePair("password", "123456"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "utf-8");
httpPost.setEntity(entity);
httpClient.execute(httpPost)

解析JSON数据

使用 JSONObject
我们在本地apache服务器定义了一组JSON数据,apache的安装可以自行百度,JSON数据如下:

[{"id":"5","version":"5.5","name":"Angry Birds"},
{"id":"6","version":"7.0","name":"Clash of Clans"},
{"id":"7","version":"3.5","name":"Hey Day"}]

解析:

public class AnalysisJSONActivity extends Activity{
        private TextView json;
        private Button getjson;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_xml);
            json=(TextView) findViewById(R.id.json);
            getjson=(Button) findViewById(R.id.getjson);
            getjson.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    getData();
                }


            });
        }
        Handler handler=new Handler(){
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case 1:
                    json.setText(msg.obj.toString());
                    break;

                default:
                    break;
                }
            };
        };
        private void getData() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    HttpURLConnection connection=null;
                    try {
                        // 指定访问的服务器地址是电脑本机
                        URL url=new URL("http://10.0.2.2/test.json");
                        connection=(HttpURLConnection) url.openConnection();
                        connection.setReadTimeout(8000);
                        connection.setRequestMethod("GET");
                        connection.setConnectTimeout(8000);
                        InputStream inputStream=connection.getInputStream();
                        BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
                        StringBuilder builder=new StringBuilder();
                        String line;
                        while ((line=reader.readLine())!=null) {
                            builder.append(line);
                        }
                        // 将服务器返回的结果存放到Message中
                        Message message=new Message();
                        message.what=1;
                        //将返回结果放到message.obj当中
                        message.obj=builder.toString();
                        handler.sendMessage(message);
                        JsonPasring(builder.toString());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }finally {
                        if(connection!=null){
                            connection.disconnect();
                        }
                    }

                }
            }).start();
        }

        private void JsonPasring(String data){
            JSONArray array;
            try {
                array = new JSONArray(data);
                for(int i=0;i<=array.length();i++){
                    JSONObject object=array.optJSONObject(i);
                    String id=object.optString("id");
                    String version=object.optString("version");
                    String name=object.optString("name");
                    Log.i("id", id);
                    Log.i("version", version);
                    Log.i("name", name);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }

        }
}

由于我们在服务器中定义的是一个 JSON 数组,因此这里首先是将服务器返回的数据传入到了一个 JSONArray 对象中。 然后循环遍历这个 JSONArray, 从中取出的每一个元素都是一个 JSONObject 对象,每个 JSONObject 对象中又会包含 id、name 和version这些数据。接下来只需要调用 optString()方法将这些数据取出,并打印出来即可

使用GOSN:

想要使用这个功能的话,则必须要在项目中添加一个GSON的Jar包。 首先我们需要将GSON的资源压缩包下载下来,下载地址是:http://code.google.com/p/google-gson/downloads/list。
JSON 格式的数据如下所示:

{"name":"Tom","age":20}

就可以定义一个 Person 类,并加入 name 和 age 这两个字段,然后只需简单地调用如下代码就可以将 JSON 数据自动解析成一个 Person 对象了:

Gson gson = new Gson();
Person person = gson.fromJson(jsonData, Person.class);

如果需要解析的是一段 JSON数组会稍微麻烦一点,我们需要借助 TypeToken将期望解析成的数据类型传入到 fromJson()方法中,如下所示:

List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>()
{}.getType());

还是上面JSONObjet的代码,换了一个方法:

private void gsonPasring(String data) {
        Gson gson = new Gson();
        List<AppBean> list = gson.fromJson(data, new TypeToken<List<AppBean>>() {}.getType());
        for(AppBean bean:list){
            String id=bean.getId();
            String ver=bean.getVersion();
            String name=bean.getName();
            Log.i("id", id);
            Log.i("name", name);
            Log.i("ver", ver);
        }
    }

同样也可以正常打印出来日志,注意:使用gson的时候对应的对象都得加上json里面的字段

对网络请求进行封装:

而发送 HTTP 请求的代码基本都是相同的,如果我们每次都去编写一遍发送 HTTP 请求的代码,这显然是非常差劲的做法。没错,通常情况下我们应该提高一下代码的复用性.写一点高质量代码.

有的可能会想到这样写:

public class HttpUtil {
        public static String sendHttpRequest(String address) {
            HttpURLConnection connection = null;
            try {
                URL url = new URL(address);
                connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(8000);
                connection.setReadTimeout(8000);
                connection.setDoInput(true);
                connection.setDoOutput(true);
                InputStream in = connection.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                StringBuilder response = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                return response.toString();
            } catch (Exception e) {
                e.printStackTrace();
                return e.getMessage();
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
    }

但是需要注意,网络请求通常都是属于耗时操作,而 sendHttpRequest()方法的内部并没有开启线程,这样就有可能导致在调用 sendHttpRequest()方法的时候使得主线程被阻塞住。
如果在 sendHttpRequest()方法内部开启一个线程那么服务器响应的数据是无法进行返回的,所有的耗时逻辑都是在子线程里进行的,sendHttpRequest()方法会在服务器还来得及响应的时候就执行结束了,当然也就无法返回响应的数据了。

使用一下Java的回调机制就可以很好的解决这个问题:
定义一个接口:

public interface HttpCallBackListener {
    void OnSuccess(String response);
    void OnError(Exception e);
}
public class HttpUtil {
    public static void get(final String url, final HttpCallBackListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL urls = new URL(url);
                    connection = (HttpURLConnection) urls.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    InputStream in = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    if (listener != null) {
                        // 回调OnSuccess方法
                        listener.OnSuccess(response.toString());
                    }
                } catch (Exception e) {
                    if (listener != null) {
                        // 回调onError()方法
                        listener.OnError(e);
                    }
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}

在activity当中可以这样写:

    HttpUtil.get("https://www.baidu.com/", new HttpCallBackListener() {

                @Override
                public void OnSuccess(String response) {
                    //服务器返回数据成功

                }

                @Override
                public void OnError(Exception e) {
                    //服务器返回数据失败

                }
            });

以上只是一个Get请求方法,当然post请求方法也是差不多。

目前常用的网络请求开源框架有:xutis ,okhttp ,volley,android-async-http等等,使用方法可以自行百度.

以上是关于Android中的网络技术基础用法的主要内容,如果未能解决你的问题,请参考以下文章

Android基础之十七使用网络技术

Android中的网络编程

Android_网络基础

WebView的基础用法

HTTPS理论基础及其在Android中的最佳实践

Android Volley入门到精通:初识Volley的基本用法