Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)

网络操作

课程介绍:

  • 掌握Android中操作网络的方式,和相关的权限设置,以及数据解析。

一、网络的基础知识

1.1客户端与服务端

  • 什么是客户端(Client)?

        享受服务的每一个用户

  • 什么是服务端(Server)?

        为客户端提供资源数据

1.2Http协议(超文本传输协议)

1.什么是Http

HTTP 协议即超文本传送协议(Hypertext Transfer Protocol )

是 Web 联网的基 础,也是手机联网常用的协议之一,HTTP 协议是建立在 TCP 协议之上的一种应用。

  • 2.Http与TCP的区别
  • 3.Http的特点及工作原理

HTTP 连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。

从建立连接到关闭连接的过程称为“一次连接”。

HTTP 提供了封装或者显示数据的具体形式。Socket 提供了网络通信的能力

  • 4.客户端与服务端的通信
  • 5.客户端浏览器解析HTML的内容

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第1张图片

1.3 URL解析

1.一个URL是有哪些部分组成

  • 协议、域名、端口、虚拟目录、参数.....

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第2张图片

二、网络请求

概要:

  • 1.从服务器获取数据
  • 2.GET请求
  • 3.POST请求
  • 4.GET VS POST

2.1如何从服务器获取数据

  1. 实例化一个URL对象
  2. 获取HttpURLConnection对象
  3. 设置请连接属性
  4. 获取响应码,判断链接结果码
  5. 读取输入流并解析

2.2GET请求 VS POST 请求

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第3张图片

GET:获取数据

相当于刷新朋友圈,返回新的朋友圈消息给你看(也可以理解去超市(相当于服务器)买东西(我要什么..),返回了笔和书本)

POST:提交数据

相当于发布一条朋友圈,发布后展示在朋友圈中(相当于把自己的东西打包后,发送给服务器,服务器更新数据展示出来)

区别:一个直接写在url上面,一个用一个盒子做起来

传输角度上:GET是明文的,POST是隐藏的,所以POST更安全

本质上:GET安全的、获取数据服务器的数据不会修改,POST提交数据,相当于写入操作服务器会被修改

幂等性:指同样的一次操作,进行一次和多次的操作对系统的资源产生的影响是一样的,GET是幂等性的,POST提交数据,会对服务器修改。

可缓存:GET获取数据是可以缓存的

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第4张图片

2.3代码演示GET请求

2.4网络操作可能遇到的注意事项

1.如果直接在主线程里面访问网络操作(因为网络是一个很耗时的操作),它会被卡死报错

  android.os.NetworkOnMainThreadException

举个例子:假如在家里面做饭,煤气灶上只有一个锅煮饭,而煮饭时间很长,

锅被卡死了,你不能锅煮其他的东西;那么就要开另外一个锅(线程)

解决方式:另开一个线程把网络访问放在这个线程里执行

new Thread(new Runnable(){
网络请求操作
}).start();

2.网络操作在新开的线程下执行,依旧会报错

Caused by: android.system.ErrnoException: android_getaddrinfo failed: EACCES (Permission denied)

解决方式:因为没有在AndroidManifest.xml中声明网络权限


3.完成以上两点再运行任然会报错

 Only the original thread that created a view hierarchy can touch its views.

因为更新UI不能再子线程里进行,只能在主线程更新UI,而网络操作又得在子线程里面进行,在主线程操作网络就会闪退

要实现子线程更新主线程的有什么办法呢?Hanlder

或者使用  runOnUiThread();或者mTextView.post(); 这两个方法都能够是更新UI操作转到主线程进行

方法1:

runOnUiThread(new Runnable(){
@Override
public void run(){
mTextView.setText(result);//更新UI的操作
}
});

方法2:

mTextView.post(new Runnable(){
@Override
public void run(){
mTextView.setText(result);//更新UI的操作
}
});

 GET完整代码

    try {
            //首先拿到URL对象
            URL url = new URL("http://www.imooc.com/api/teacher?type=2&page=1");
            //打开url对象的链接,获得connection链接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //设置超时时间30s
            connection.setConnectTimeout(30 * 1000);
            //设置请求方法类型 GET请求获取数据
            connection.setRequestMethod("POST");
            //设置请求的属性
            //我希望拿到内容的格式是json
            connection.setRequestProperty("Content-Type", "application/json");
            //我希望拿到的字符集是UTF-8
            connection.setRequestProperty("Charset", "UTF-8");
            //我们希望接受到的字符集是UTF-8
            connection.setRequestProperty("Accept-Charset", "UTF-8");
            //发起连接
            connection.connect();
            //连接开始后
            //获取信息
            //获取请求码
            int responseCode = connection.getResponseCode();
            //拿到消息
            String repsonseMessage = connection.getResponseMessage();
            //如果请求成功
            if (responseCode == HttpURLConnection.HTTP_OK) {//如果拿到请求码为200(HTTP_OK)
                //拿到输入流
                InputStream inputStream=connection.getInputStream();
                //将将流转换成字符串
                result = streamToString(inputStream);
                //更新UI只能在主线程操作
                //通过使用runOnUiThread()方法将更新UI操作放到主线程进行
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //将数据转化成UTF-8的格式
                        result=decode(result);
                        //将拿到的数据展示出来(更新UI)
                        mTextView.setText(result);
                    }
                });

            }else{//如果请求失败
                //TODO:error fail
                Log.e(TAG,"run:error code"+responseCode+",message:"+repsonseMessage);

            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第5张图片

2.5POST请求

与GET不一样,它不是直接把参数放在URL上,而是把数据打包好

  //首先拿到URL对象type=2&page=1
            URL url = new URL("http://www.imooc.com/api/teacher");

使用POST还要多加一些设置

   //*使用POST还有设置运行的输入输出
            connection.setDoOutput(true);
            connection.setDoInput(true);
            //POST不能使用缓存
            connection.setUseCaches(false);

POST请求的数据打包 

 //*POST请求数据打包
            String data = "username=" + getEncodeValue("abc") + "&number=" + getEncodeValue("123456");
            //输出流写入数据
            OutputStream outputStream = connection.getOutputStream();
            //将我的打包好的数据写入
            outputStream.write(data.getBytes());
            outputStream.flush();//如果没满,要调用flush()方法:刷新释放缓冲区的资源
            outputStream.close();//用完关闭,防止内存泄漏

POST完整代码:

  try {
            //首先拿到URL对象type=2&page=1
            URL url = new URL("http://www.imooc.com/api/teacher");
            //打开url对象的链接,获得connection链接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //设置超时时间30s
            connection.setConnectTimeout(30 * 1000);
            //设置请求方法类型 GET请求获取数据
            connection.setRequestMethod("POST");
            //设置请求的属性
            //我希望拿到内容的格式是json
            connection.setRequestProperty("Content-Type", "application/json");
            //我希望拿到的字符集是UTF-8
            connection.setRequestProperty("Charset", "UTF-8");
            //我们希望接受到的字符集是UTF-8
            connection.setRequestProperty("Accept-Charset", "UTF-8");

            //*使用POST还有设置运行的输入输出
            connection.setDoOutput(true);
            connection.setDoInput(true);
            //POST不能使用缓存
            connection.setUseCaches(false);

            //发起连接
            connection.connect();

            //*POST请求数据打包
            String data = "username=" + getEncodeValue("abc") + "&number=" + getEncodeValue("123456");
            //输出流写入数据
            OutputStream outputStream = connection.getOutputStream();
            //将我的打包好的数据写入
            outputStream.write(data.getBytes());
            outputStream.flush();//如果没满,要调用flush()方法:刷新释放缓冲区的资源
            outputStream.close();//用完关闭,防止内存泄漏

            //连接开始后
            //获取信息
            //获取请求码
            int responseCode = connection.getResponseCode();
            //拿到消息
            String repsonseMessage = connection.getResponseMessage();
            //如果请求成功
            if (responseCode == HttpURLConnection.HTTP_OK) {//如果拿到请求码为200(HTTP_OK)
                //拿到输入流
                InputStream inputStream=connection.getInputStream();
                //将将流转换成字符串
                result = streamToString(inputStream);
                //更新UI只能在主线程操作
                //通过使用runOnUiThread()方法将更新UI操作放到主线程进行
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //将数据转化成UTF-8的格式
                        result=decode(result);
                        //将拿到的数据展示出来(更新UI)
                        mTextView.setText(result);
                    }
                });

            }else{//如果请求失败
                //TODO:error fail
                Log.e(TAG,"run:error code"+responseCode+",message:"+repsonseMessage);

            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

 三、数据解析

Json数据解析

Json 全称 JavaScript Object Natation ,用来描述数据结构,它是基于纯文本的数据格式,是一种轻量级的数据交换格式。广泛应用于 服务端 与 客户端 的数据交互。

  • 格式

    Json 以 key-value的形式存储数据;

    Key的取值 为 String 类型;

    Value的取值 为 String,boolean,Number,数组,Object,null;

    Json 串 以 { 开始, 以 } 结尾;

    Json 串中 数组 是 以 [ 开始, 以 ] 结尾;

    Json 串中 Object 是 以 { 开始, 以 } 结尾;

下面是GET请求获取到URL:http://www.imooc.com/api/teacher?type=2&page=1 中的json数据

其中status:1 表示是int型的;“ ”表示是字符串型的;true or false表示是boolean类型的

data:[ ]是一个数组

data数组里面又有很多对象,对象里面又有属性

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第6张图片 首先建一个完全映射这个json格式的类

/**
 * 完全映射json
 */
public class LessonResult {
    //status:1表示整形,如果是"",表示String,如果是true or false表示boolean
    private int mStatus;
    //data:[]是一个数组,数组里面又包含很多对象,lesson是对应很多对象
    private List mLessons;

    public int getStatus() {
        return mStatus;
    }

    public void setStatus(int status) {
        mStatus = status;
    }

    public List getLessons() {
        return mLessons;
    }


    public void setLessons(List lessons) {
        mLessons = lessons;
    }

    @Override
    public String toString() {
        return "LessonResult{" +
                "mStatus=" + mStatus +
                ", mLessons=" + mLessons +
                '}';
    }


    //data数组里面的对象类
    public static class Lesson {
        private int mID;//获取数组data里面的id
        private int mLearnerNumber;//获取数组data里面的LearnerNumber
        private String mName;//
        private String mSmallPictureUrl;
        private String mBigPictureUrl;
        private String mDescription;


        public int getmID() {
            return mID;
        }

        public void setmID(int mID) {
            this.mID = mID;
        }

        public int getmLearnerNumber() {
            return mLearnerNumber;
        }

        public void setmLearnerNumber(int mLearnerNumber) {
            this.mLearnerNumber = mLearnerNumber;
        }

        public String getmName() {
            return mName;
        }

        public void setmName(String mName) {
            this.mName = mName;
        }

        public String getmSmallPictureUrl() {
            return mSmallPictureUrl;
        }

        public void setmSmallPictureUrl(String mSmallPictureUrl) {
            this.mSmallPictureUrl = mSmallPictureUrl;
        }

        public String getmBigPictureUrl() {
            return mBigPictureUrl;
        }

        public void setmBigPictureUrl(String mBigPictureUrl) {
            this.mBigPictureUrl = mBigPictureUrl;
        }

        public String getmDescription() {
            return mDescription;
        }

        public void setmDescription(String mDescription) {
            this.mDescription = mDescription;
        }


        @Override
        public String toString() {
            return "Lesson{" +
                    "mID=" + mID +
                    ", mLearnerNumber=" + mLearnerNumber +
                    ", mName='" + mName + '\'' +
                    ", mSmallPictureUrl='" + mSmallPictureUrl + '\'' +
                    ", mBigPictureUrl='" + mBigPictureUrl + '\'' +
                    ", mDescription='" + mDescription + '\'' +
                    '}';
        }
    }
}

通过代码一步一步获取json的数据,再返回到上面的类,通过toString方式显示出来

快速生成getter和setter方法,生成toString方法 MAC快捷键command+N;

try {

            //新建一个jsonObject对象,获取我们GET请求得到的result(json格式)
            JSONObject jsonObject = new JSONObject(result);
           //读取json对象里面的status
            int status = jsonObject.getInt("status");
            LessonResult lessonResult = new LessonResult();
            lessonResult.setStatus(status);//将读到的status给对象赋值

            //读取json里面的数组,名称是data
            JSONArray lessons = jsonObject.getJSONArray("data");
            //创建一个List每一次都把Item里面的数据添加进去
            List lessonList = new ArrayList<>();
            //因为data数组里面还有很多对象,所以要循环取出
            if (lessons != null && lessons.length() > 0) {
                for (int index = 0; index < lessons.length(); index++) {
                    //拿到data里面的每一个item
                    JSONObject lesson = (JSONObject) lessons.get(index);
                    //拿到每一个item里面的对象的变量
                    int id = lesson.getInt("id");
                    int learner = lesson.getInt("learner");
                    String name = lesson.getString("name");
                    String smallPic = lesson.getString("picSmall");
                    String bigPic = lesson.getString("picBig");
                    String description = lesson.getString("description");
                    //把所有数据拿到后给对象赋值
                    LessonResult.Lesson lessonItem = new LessonResult.Lesson();
                    lessonItem.setmID(id);
                    lessonItem.setmName(name);
                    lessonItem.setmSmallPictureUrl(smallPic);
                    lessonItem.setmBigPictureUrl(bigPic);
                    lessonItem.setmDescription(description);
                    lessonItem.setmLearnerNumber(learner);
                    lessonList.add(lessonItem);//每一次都把数据添加到List里面
                }
                //循环结束把lessonList设置到Lessons里面
                lessonResult.setLessons(lessonList);
            }

            mTextView.setText(lessonResult.toString());

        } catch (JSONException e) {
            e.printStackTrace();
        }

Android进阶:网络与数据存储—步骤1:Android网络与通信(第1小节:网络操作)_第7张图片

使用Gson解析数据,谷歌的json解析;

 

你可能感兴趣的:(2-android进阶)