一、网络基础知识
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请求
目标:
下载并安装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:把数据打包起来,然后再传过去
全部代码:
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();
}
}
效果图: