Android之网络操作GET、POST

一、网络基础知识

1、客户端与服务端
2、Http协议
3、URL解析


客户端与服务端

举例:外卖软件。我们是客户——客服端,服务端——为我们提供服务,外卖软件背后的商家。

服务端为客户端提供资源、数据。


Http协议

全称:HyperText Transfer Protocol 超文本传输协议
在这里插入图片描述
Http与TCP的区别:
Http:应用层的协议
TCP:传输层的协议(更底层的)


URL解析

1、一个URL由哪些部分组成?
组成部分:(?后面是键值对)
协议、域名、端口、虚拟目录、参数…
在这里插入图片描述
举例URL:
https://www.imooc.com/search/?type=course&words=android
分析:
https://www.imooc.com——慕课网
https://www.imooc.com/search——到了search功能的虚拟目录
https://www.imooc.com/search/?type=course&words=android——查找类型为课程,关键字是android


二、Android中的网络操作

1、从服务器获取数据
2、GET请求
3、POST请求


从服务器获取数据

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


GET VS POST

在这里插入图片描述
在这里插入图片描述
举例:
一个人拿着(参数)一支笔,一本书直接去往目的地,而另一个人拿着箱子(箱子里装着一支笔,一本书)去往目的地(传输POST安全)

GET是请求,服务器没有变更;POST提交数据,有一个写入操作,对服务器数据有修改(本质上GET安全)

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


三、GET请求

目标:
在这里插入图片描述

URL

如何修改图片大小

下载并安装chrome json格式化插件,将数据展示为json格式


具体代码:

activity_network.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/getButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取数据"
        android:textSize="20sp"
        android:layout_gravity="center_horizontal"
        />

    <Button
        android:id="@+id/parseDataButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="解析数据"
        android:textSize="20sp"
        android:layout_gravity="center_horizontal"
        />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:hint="结果"
        android:textSize="20sp"
        android:textStyle="bold"
        android:layout_gravity="center"
        />

</LinearLayout>

NetworkActivity

public class NetworkActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mGetButton;
    private Button mParseDataButton;
    private TextView mTextView;
    private final String TAG="NetworkActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network);

        findViews();
        setListeners();
    }


    /**
     * 获取控件
     */
    private void findViews(){
        Button mGetButton= (Button)findViewById(R.id.getButton);
        Button mParseDataButton= (Button)findViewById(R.id.parseDataButton);
        TextView mTextView= (TextView)findViewById(R.id.textView);
    }

    /**
     * 为按钮设置点击事件
     */
    private void setListeners(){

        mGetButton.setOnClickListener(this);
        mParseDataButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.getButton:
                try {
                    //实例化一个URL对象
                    URL url=new URL("https://www.imooc.com/api/teacher?type=2&page=1");

                    //获取HttpURLConnection对象
                    HttpURLConnection connection= (HttpURLConnection) url.openConnection();

                    //设置超时时间:超过30s还没有成功,就默认失败
                    connection.setConnectTimeout(30*1000);//30s,默认单位:毫秒

                    //设置请求方法类型
                    connection.setRequestMethod("GET");

                    //设置请求属性
                    //内容类型为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 responseMessage=connection.getResponseMessage();

                    if(responseCode==HttpURLConnection.HTTP_OK){//HTTP_OK=200
                        //流
                        InputStream inputStream=connection.getInputStream();
                        String result=streamToString(inputStream);
                    }


                } catch (MalformedURLException e) {//抛出不合法URL异常
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.parseDataButton:

                break;
        }
    }


    /**
     * 将输入流转换成字符串
     * @param is 从网络获取的输入流
     * @return 字符串
     */
    public String streamToString(InputStream is){

        try{
            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len;
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            baos.close();
            is.close();
            byte[] byteArray=baos.toByteArray();
            return new String(byteArray);

        }catch (Exception e){
            Log.d(TAG, e.toString());
            return null;
        }
    }

    /**
     * 将Unicode字符转换为UTF-8类型字符串
     */
    public static String decode(String unicodeStr) {
        if (unicodeStr == null) {
            return null;
        }
        StringBuilder retBuf = new StringBuilder();
        int maxLoop = unicodeStr.length();
        for (int i = 0; i < maxLoop; i++) {
            if (unicodeStr.charAt(i) == '\\') {
                if ((i < maxLoop - 5)
                        && ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr
                        .charAt(i + 1) == 'U')))
                    try {
                        retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16));
                        i += 5;
                    } catch (NumberFormatException localNumberFormatException) {
                        retBuf.append(unicodeStr.charAt(i));
                    }
                else {
                    retBuf.append(unicodeStr.charAt(i));
                }
            } else {
                retBuf.append(unicodeStr.charAt(i));
            }
        }
        return retBuf.toString();
    }

}


运行程序出现闪退: android.os.NetworkOnMainThreadException

我们的网络是在MainThread(主线程),安卓的应用程序可以同时有多个进程,每个进程里又有多个线程,但是UI的响应(界面的响应)是在一个线程里(主线程),如果在主线程里去访问网络(网络是一个很耗时的操作),比如在此代码中,设置代码超时时间为30s,可能要30s才到达,相当于我们的UI线程被卡死了(阻塞),那我们去触摸屏幕上的按钮的时候,就相当于没有响应)。

用做饭为例:
煤气灶上有一个锅,用于煮饭,如果煮饭的时候很长(30分钟),在这30分钟内就不能做其他事情了,所以,如果有很耗时的操作(煮饭),又想要做其他事(炒菜),这时应该用另外一个锅(即另开一个线程):一个锅煮饭,另一个锅炒菜。

代码修改:

NetworkActivity中的onClick()方法

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

          new Thread(new Runnable() {
              @Override
              public void run() {

                  try {
                      URL url=new URL("https://www.imooc.com/api/teacher?type=2&page=1");
                      HttpURLConnection connection= (HttpURLConnection) url.openConnection();
                      connection.setConnectTimeout(30*1000);//设置超时时间为30秒
                      connection.setRequestMethod("GET");//设置请求方法类型

                      connection.setRequestProperty("Content-Type","application/json");//设置请求属性,用键值对表示,设置数据类型是json格式的
                      connection.setRequestProperty("Charset","UTF-8");//设置我期望拿到的数据集是UTF-8格式
                      connection.setRequestProperty("Accept-Charset","UTF-8");//设置接收到的字符集是UTF-8

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

		              /*
		              发起连接之后,就可以去获取一些信息
		               */
                      int responseCode=connection.getResponseCode();//获取响应码:通过响应码知晓连接状态
                      String responseMessage=connection.getResponseMessage();//返回连接的一些消息,比如:超时、错误等

		              /*
		              拿到信息后,进行相应的判断
		               */
                      if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
                          InputStream inputStream=connection.getInputStream();//拿到数据
                          String result=streamToString(inputStream);//让数据从输入流转换成字符串,得到结果
                      }




                  } catch (MalformedURLException e) {//不合法的URL异常
                      e.printStackTrace();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }

              }
          }).start();

          break;


      case R.id.parseDataButton:

          break;
  }
}

运行程序出现闪退:java.lang.SecurityException: Permission denied (missing INTERNET permission?)

使用网络时,必须要申请Internet权限

代码修改:

AndroidManifest.xml

 <uses-permission android:name="android.permission.INTERNET"/>

将结果展示出来:

代码修改:

NetworkActivity中onClick()方法

/*
拿到信息后,进行相应的判断
 */
if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
    InputStream inputStream=connection.getInputStream();//拿到数据
    String result=streamToString(inputStream);//让数据从输入流转换成字符串,得到结果

    mTextView.setText(result);//将结果展示出来
}
else{//连接失败,显示失败的信息
    //TODO: error fail
    //输出响应码和信息
    Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

}


运行程序出现闪退: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

只能在原始线程(主线程)点击控件。
如果我们要更新UI,只能在主线程更新UI, 但我们又在子线程进行了操作。

问题: 在主线程操纵网络,闪退。在子线程操纵网络,没有问题,但更新UI会出现闪退
解决: 在子线程能更新主线程的UI

ps:也可以使用handler实现”在子线程更新主线程UI“功能

代码修改:

NetworkActivity中onClick()方法

第一种修改办法:
在Activity有一个方法:
runOnUiThread() 直接运行在UI的线程里,可以帮忙转换到主线程里(底层是用handler实现的)

if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
   InputStream inputStream=connection.getInputStream();//拿到数据
   //让数据从输入流转换成字符串,得到结果
   mResult = streamToString(inputStream);

   //在子线程更新主线程的UI,借助Activity的 runOnUiThread() 方法
   runOnUiThread(new Runnable() {
       @Override
       public void run() {
           mTextView.setText(mResult);//将结果展示出来
       }
   });
}
else{//连接失败,显示失败的信息
   //TODO: error fail
   //输出响应码和信息
   Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

}

第二种修改办法:
在TextView有一个方法:
post() 直接运行在主线程里(底层是用handler实现的)

if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
   InputStream inputStream=connection.getInputStream();//拿到数据
   //让数据从输入流转换成字符串,得到结果
   mResult = streamToString(inputStream);

   //在子线程更新主线程的UI,借助TextView的 post() 方法
   mTextView.post(new Runnable() {
     @Override
      public void run() {
          mTextView.setText(mResult);//将结果展示出来
      }
  });
}
else{//连接失败,显示失败的信息
   //TODO: error fail
   //输出响应码和信息
   Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

}

点击“获取数据”按钮,效果图:
在这里插入图片描述


乱码,是Unicode字符,要转换成UTF-8

代码修改:

NetworkActivity中onClick()方法

 //请求网络成功
if(responseCode==HttpURLConnection.HTTP_OK){//HTTP_OK=200
	 //流
	 InputStream inputStream=connection.getInputStream();
	 mResult = streamToString(inputStream);
	
	 //帮忙转换到主线程里
	 runOnUiThread(new Runnable() {
	     @Override
	     public void run() {
	     	 //结果是Unicode字符,先转换成UTF-8,再展示
 			 mResult=decode(mResult);
	         //将数据展示出来
	         mTextView.setText(mResult);
	     }  
 	});
}

在这里插入图片描述


四、POST请求

将NetworkActivity的onClick()方法中try-catch代码提取成requestDataByGet()方法:

private void requestDataByGet() {
  try {
      URL url=new URL("https://www.imooc.com/api/teacher?type=2&page=1");
      HttpURLConnection connection= (HttpURLConnection) url.openConnection();
      connection.setConnectTimeout(30*1000);//设置超时时间为30秒
      connection.setRequestMethod("GET");//设置请求方法类型

      connection.setRequestProperty("Content-Type","application/json");//设置请求属性,用键值对表示,设置数据类型是json格式的
      connection.setRequestProperty("Charset","UTF-8");//设置我期望拿到的数据集是UTF-8格式
      connection.setRequestProperty("Accept-Charset","UTF-8");//设置接收到的字符集是UTF-8

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

      /*
      发起连接之后,就可以去获取一些信息
       */
      int responseCode=connection.getResponseCode();//获取响应码:通过响应码知晓连接状态
      String responseMessage=connection.getResponseMessage();//返回连接的一些消息,比如:超时、错误等

      /*
      拿到信息后,进行相应的判断
       */
      if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
          InputStream inputStream=connection.getInputStream();//拿到数据
          //让数据从输入流转换成字符串,得到结果
          mResult = streamToString(inputStream);

          //第一种方法:在子线程更新主线程的UI,借助Activity的 runOnUiThread() 方法
          runOnUiThread(new Runnable() {
              @Override
              public void run() {

                  mResult=decode(mResult);//结果是Unicode字符,先转换成UTF-8,再展示

                  mTextView.setText(mResult);//将结果展示出来
              }
          });

          //第二种方法:在子线程更新主线程的UI,借助TextView的 post() 方法
//                                mTextView.post(new Runnable() {
//                                    @Override
//                                    public void run() {
//                                        mTextView.setText(mResult);//将结果展示出来
//                                    }
//                                });
      }
      else{//连接失败,显示失败的信息
          //TODO: error fail
          //输出响应码和信息
          Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

      }




  } catch (MalformedURLException e) {//不合法的URL异常
      e.printStackTrace();
  } catch (IOException e) {
      e.printStackTrace();
  }
}

相应的onClick()方法变成:

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

          new Thread(new Runnable() {
              @Override
              public void run() {
                  requestDataByGet();
              }
          }).start();

          break;

      case R.id.parseDataButton:
          
          break;
  }
}

POST代码和GET代码差不多

requestDataByPost()方法:

1、将请求方法类型从GET修改成POST:
connection.setRequestMethod("POST");

2、新增几个配置:

设置运行的输入输出
connection.setDoOutput(true); connection.setDoInput(true);

Post方式不能缓存,需手动设置为false
connection.setUseCaches(false);

3、打包请求数据:相当于之前讲的,把参数封装进盒子里,再把盒子提交上去

举个🌰:登录或者注册时,我们需要提交用户名、手机号等。怎么提取?封装起来。
String data="username=imooc & number=15088886666";

username–>key imooc–>value, value可能会出现编码错误,改进:

为什么请求时,需要使用URLEncode做encode转码操作

String data= "username=" + getEncodeValue("imooc") + " & number="+getEncodeValue("15088886666");

getEncodeValue()方法

private String getEncodeValue(String imooc) {

   String encode = null;
   try {
       encode = URLEncoder.encode(imooc, "UTF-8");//对参数进行处理
   } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
   }
   return encode;//将imooc提取成参数:opt+cmd+p
}

4、参数处理
URL不直接暴露参数
URL url=new URL("https://www.imooc.com/api/teacher");

获取输出流
OutputStream outputStream=connection.getOutputStream();

将封装的小盒子里的参数提交上去
outputStream.write(data.getBytes());

outputStream.flush();
outputStream.close();

5、剩下的处理和GET一模一样

requestDataByPost()方法

private void requestDataByPost() {
  try {
      //?type=2&page=1
      URL url=new URL("https://www.imooc.com/api/teacher");
      HttpURLConnection connection= (HttpURLConnection) url.openConnection();
      connection.setConnectTimeout(30*1000);//设置超时时间为30秒
      connection.setRequestMethod("POST");//设置请求方法类型

      connection.setRequestProperty("Content-Type","application/json");//设置请求属性,用键值对表示,设置数据类型是json格式的
      connection.setRequestProperty("Charset","UTF-8");//设置我期望拿到的数据集是UTF-8格式
      connection.setRequestProperty("Accept-Charset","UTF-8");//设置接收到的字符集是UTF-8

      //新增几个配置:
      connection.setDoOutput(true);//设置运行的输入输出
      connection.setDoInput(true);
      connection.setUseCaches(false); // Post方式不能缓存,需手动设置为false

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


      /*
      打包请求数据:相当于之前讲的,把参数封装进盒子里,再把盒子提交上去
       */
      String data= "username=" + getEncodeValue("imooc") + " & number="+getEncodeValue("15088886666");

      // 获取输出流
      OutputStream outputStream=connection.getOutputStream();
      outputStream.write(data.getBytes());//将封装的小盒子里的参数提交上去
      outputStream.flush();
      outputStream.close();

      /*
      发起连接之后,就可以去获取一些信息
       */
      int responseCode=connection.getResponseCode();//获取响应码:通过响应码知晓连接状态
      String responseMessage=connection.getResponseMessage();//返回连接的一些消息,比如:超时、错误等

      /*
      拿到信息后,进行相应的判断
       */
      if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
          InputStream inputStream=connection.getInputStream();//拿到数据
          //让数据从输入流转换成字符串,得到结果
          mResult = streamToString(inputStream);

          //第一种方法:在子线程更新主线程的UI,借助Activity的 runOnUiThread() 方法
          runOnUiThread(new Runnable() {
              @Override
              public void run() {

                  mResult=decode(mResult);//结果是Unicode字符,先转换成UTF-8,再展示

                  mTextView.setText(mResult);//将结果展示出来
              }
          });

          //第二种方法:在子线程更新主线程的UI,借助TextView的 post() 方法
//                                mTextView.post(new Runnable() {
//                                    @Override
//                                    public void run() {
//                                        mTextView.setText(mResult);//将结果展示出来
//                                    }
//                                });
      }
      else{//连接失败,显示失败的信息
          //TODO: error fail
          //输出响应码和信息
          Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

      }




  } catch (MalformedURLException e) {//不合法的URL异常
      e.printStackTrace();
  } catch (IOException e) {
      e.printStackTrace();
  }
}

首页是GET,登录注册是POST。登录注册也能用GET,只不过我们的手机号、邮箱、密码是敏感信息,(GET在URL后直接拼接参数),会暴露这些信息

GET:直接拼接;POST:把数据打包起来,然后再传过去

GET和POST的区别


JSON数据

全部代码:

LessonResult类

package com.example.getstudy;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by TMJ on 2020-02-13.
 */

//https://www.imooc.com/api/teacher?type=2&page=1
    //完全映射JSON

public class LessonResult {

    private int mStatus;
    private List<Lesson> mLessons;

    public int getStatus() {
        return mStatus;
    }

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

    public List<Lesson> getLessons() {
        return mLessons;
    }

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

    public static class Lesson{
        private int mID;
        private String mName;
        private String mSmallPictureUrl;
        private String mBigPictureUrl;
        private String mDescription;
        private int mLearnerNumber;

        public int getID() {
            return mID;
        }

        public void setID(int ID) {
            mID = ID;
        }

        public String getName() {
            return mName;
        }

        public void setName(String name) {
            mName = name;
        }

        public String getSmallPictureUrl() {
            return mSmallPictureUrl;
        }

        public void setSmallPictureUrl(String smallPictureUrl) {
            mSmallPictureUrl = smallPictureUrl;
        }

        public String getBigPictureUrl() {
            return mBigPictureUrl;
        }

        public void setBigPictureUrl(String bigPictureUrl) {
            mBigPictureUrl = bigPictureUrl;
        }

        public String getDescription() {
            return mDescription;
        }

        public void setDescription(String description) {
            mDescription = description;
        }

        public int getLearnerNumber() {
            return mLearnerNumber;
        }

        public void setLearnerNumber(int learnerNumber) {
            mLearnerNumber = learnerNumber;
        }

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

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

NetworkActivity

package com.example.getstudy;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;


public class NetworkActivity extends AppCompatActivity implements View.OnClickListener {

    private Button mGetButton;
    private Button mParseDataButton;
    private TextView mTextView;
    private final String TAG="NetworkActivity";
    private String mResult;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_network);

        findViews();
        setListeners();

    }

    /**
     * 获取控件
     */
    private void findViews(){
        mGetButton= (Button)findViewById(R.id.getButton);
        mParseDataButton= (Button)findViewById(R.id.parseDataButton);
        mTextView= (TextView)findViewById(R.id.textView);
    }


    /**
     * 为按钮设置点击事件
     */
    private void setListeners(){

        mGetButton.setOnClickListener(this);
        mParseDataButton.setOnClickListener(this);
    }

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

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        requestDataByGet();



                    }
                }).start();

                break;

            case R.id.parseDataButton:

                handleJSONData(mResult);
                break;
        }
    }

    private void handleJSONData(String result) {

        try {
            //让读取的数据构造一个LessonResult
            LessonResult lessonResult=new LessonResult();
            //怎么处理成一个对象
            JSONObject jsonObject=new JSONObject(result);//由result直接转换成的JSON对象(key-value形式)(最外层的大括号)
            List<LessonResult.Lesson> lessonList=new ArrayList<>();
            //怎么读取数据
            int status=jsonObject.getInt("status");

            //赋值
            lessonResult.setStatus(status);

            JSONArray lessons=jsonObject.getJSONArray("data");
            //怎么读取data(数组)里的数据
            if(lessons != null && lessons.length() > 0){
                for (int index = 0; index < lessons.length(); index++) {
                    //将内层的大括号处理成对象
                    JSONObject lesson = (JSONObject) lessons.get(index);
                    //读取数据
                    int id = lesson.getInt("id");
                    int learner = lesson.getInt("learner");
                    String name = lesson.getString("name");
                    String picSmall = lesson.getString("picSmall");
                    String picBig = lesson.getString("picBig");
                    String description = lesson.getString("description");

                    LessonResult.Lesson lessonItem = new LessonResult.Lesson();

                    //赋值,构建一个lessonItem对象
                    lessonItem.setID(id);
                    lessonItem.setName(name);
                    lessonItem.setSmallPictureUrl(picSmall);
                    lessonItem.setBigPictureUrl(picBig);
                    lessonItem.setDescription(description);
                    lessonItem.setLearnerNumber(learner);

                    //添加对象
                    lessonList.add(lessonItem);

                }
                //赋值
                lessonResult.setLessons(lessonList);
            }
            //设置输出结果
            mTextView.setText(lessonResult.toString());

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

    private void requestDataByGet() {
        try {
            URL url=new URL("https://www.imooc.com/api/teacher?type=2&page=1");
            HttpURLConnection connection= (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(30*1000);//设置超时时间为30秒
            connection.setRequestMethod("GET");//设置请求方法类型

            connection.setRequestProperty("Content-Type","application/json");//设置请求属性,用键值对表示,设置数据类型是json格式的
            connection.setRequestProperty("Charset","UTF-8");//设置我期望拿到的数据集是UTF-8格式
            connection.setRequestProperty("Accept-Charset","UTF-8");//设置接收到的字符集是UTF-8

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

            /*
            发起连接之后,就可以去获取一些信息
             */
            int responseCode=connection.getResponseCode();//获取响应码:通过响应码知晓连接状态
            String responseMessage=connection.getResponseMessage();//返回连接的一些消息,比如:超时、错误等

            /*
            拿到信息后,进行相应的判断
             */
            if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
                InputStream inputStream=connection.getInputStream();//拿到数据
                //让数据从输入流转换成字符串,得到结果
                mResult = streamToString(inputStream);

                //第一种方法:在子线程更新主线程的UI,借助Activity的 runOnUiThread() 方法
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        mResult=decode(mResult);//结果是Unicode字符,先转换成UTF-8,再展示

                        mTextView.setText(mResult);//将结果展示出来
                    }
                });

                //第二种方法:在子线程更新主线程的UI,借助TextView的 post() 方法
//                                mTextView.post(new Runnable() {
//                                    @Override
//                                    public void run() {
//                                        mTextView.setText(mResult);//将结果展示出来
//                                    }
//                                });
            }
            else{//连接失败,显示失败的信息
                //TODO: error fail
                //输出响应码和信息
                Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

            }




        } catch (MalformedURLException e) {//不合法的URL异常
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void requestDataByPost() {
        try {
            //?type=2&page=1
            URL url=new URL("https://www.imooc.com/api/teacher");
            HttpURLConnection connection= (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(30*1000);//设置超时时间为30秒
            connection.setRequestMethod("POST");//设置请求方法类型

            connection.setRequestProperty("Content-Type","application/json");//设置请求属性,用键值对表示,设置数据类型是json格式的
            connection.setRequestProperty("Charset","UTF-8");//设置我期望拿到的数据集是UTF-8格式
            connection.setRequestProperty("Accept-Charset","UTF-8");//设置接收到的字符集是UTF-8

            //新增几个配置:
            connection.setDoOutput(true);//设置运行的输入输出
            connection.setDoInput(true);
            connection.setUseCaches(false); // Post方式不能缓存,需手动设置为false

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


            /*
            打包请求数据:相当于之前讲的,把参数封装进盒子里,再把盒子提交上去
             */
            String data= "username=" + getEncodeValue("imooc") + " & number="+getEncodeValue("15088886666");

            // 获取输出流
            OutputStream outputStream=connection.getOutputStream();
            outputStream.write(data.getBytes());//将封装的小盒子里的参数提交上去
            outputStream.flush();
            outputStream.close();

            /*
            发起连接之后,就可以去获取一些信息
             */
            int responseCode=connection.getResponseCode();//获取响应码:通过响应码知晓连接状态
            String responseMessage=connection.getResponseMessage();//返回连接的一些消息,比如:超时、错误等

            /*
            拿到信息后,进行相应的判断
             */
            if(responseCode == HttpURLConnection.HTTP_OK){//HTTP_OK:200,表明连接成功
                InputStream inputStream=connection.getInputStream();//拿到数据
                //让数据从输入流转换成字符串,得到结果
                mResult = streamToString(inputStream);

                //第一种方法:在子线程更新主线程的UI,借助Activity的 runOnUiThread() 方法
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {

                        mResult=decode(mResult);//结果是Unicode字符,先转换成UTF-8,再展示

                        mTextView.setText(mResult);//将结果展示出来
                    }
                });

                //第二种方法:在子线程更新主线程的UI,借助TextView的 post() 方法
//                                mTextView.post(new Runnable() {
//                                    @Override
//                                    public void run() {
//                                        mTextView.setText(mResult);//将结果展示出来
//                                    }
//                                });
            }
            else{//连接失败,显示失败的信息
                //TODO: error fail
                //输出响应码和信息
                Log.d(TAG, "run: error code:"+responseCode+",message:"+responseMessage);

            }




        } catch (MalformedURLException e) {//不合法的URL异常
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 有的时候用户传入的字符可能不是UTF-8格式的,作一个编码
     * @param imooc
     * @return
     */
    @NonNull
    private String getEncodeValue(String imooc) {

        String encode = null;
        try {
            encode = URLEncoder.encode(imooc, "UTF-8");//对参数进行处理
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encode;//将imooc提取成参数:opt+cmd+p
    }


    /**
     * 将输入流转换成字符串
     * @param is 从网络获取的输入流
     * @return 字符串
     */
    public String streamToString(InputStream is){

        try{
            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int len;
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            baos.close();
            is.close();
            byte[] byteArray=baos.toByteArray();
            return new String(byteArray);

        }catch (Exception e){
            Log.d(TAG, e.toString());
            return null;
        }
    }

    /**
     * 将Unicode字符转换为UTF-8类型字符串
     */
    public static String decode(String unicodeStr) {
        if (unicodeStr == null) {
            return null;
        }
        StringBuilder retBuf = new StringBuilder();
        int maxLoop = unicodeStr.length();
        for (int i = 0; i < maxLoop; i++) {
            if (unicodeStr.charAt(i) == '\\') {
                if ((i < maxLoop - 5)
                        && ((unicodeStr.charAt(i + 1) == 'u') || (unicodeStr
                        .charAt(i + 1) == 'U')))
                    try {
                        retBuf.append((char) Integer.parseInt(unicodeStr.substring(i + 2, i + 6), 16));
                        i += 5;
                    } catch (NumberFormatException localNumberFormatException) {
                        retBuf.append(unicodeStr.charAt(i));
                    }
                else {
                    retBuf.append(unicodeStr.charAt(i));
                }
            } else {
                retBuf.append(unicodeStr.charAt(i));
            }
        }
        return retBuf.toString();
    }

}

效果图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值