三三要成为安卓糕手
引入:在Android中发起网络请求
在Android中可以使用HttpURLConnection、OkHttp、Retrofit等常见的请求方式:
- HttpURLConnection:Android自带的网络请求方式,使用起来较为复杂,但自由度更高,适合尽量减少外部依赖的项目;
- OkHttp:适合绝大多数Android项目,特别是在需要高效处理网络请求的场景中;
- Retrofit:在OkHttp的基础上做了封装,代码更加简洁明了;
- Volley:Google推出的网络请求库,目前不经常被用到。
一:需求
查询用户4,点击发起Get请求,形成http数据传输,接收从后端返回的用户数据
预期结果如下
二:http传输三个问题
要想进行http明文传输,需要解决三个问题
- 清单文件中声明网络访问权限
- 设置可以明文传输
- 不要在主线程中进行http连接访问
public class HttpUrlConnectionActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "HttpUrlConnectionActivity";
private EditText etUserId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_http_url_connection);
findViewById(R.id.btn_get).setOnClickListener(HttpUrlConnectionActivity.this);
etUserId = findViewById(R.id.et_user_id);
}
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
if (v.getId() == R.id.btn_get) {
//这个过程真的非常的惊艳
String id = etUserId.getText().toString();
String urlAddress = "http://titok.fzqq.fun/addons/cms/api.user/userInfo?user_id=" + id + "&type=archives";
Log.i(TAG, "urlAddress:"+urlAddress);
try {
//创建URL对象,传入服务器地址
URL url = new URL(urlAddress);
//打开连接,HttpURLConnection对象中设置一些连接的属性:比如请求方法和连接时间,读取数据的时间
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//连接方法
connection.setRequestMethod("GET");
//连接超时时间
connection.setConnectTimeout(8000);
//读取超时时间
connection.setReadTimeout(80000);
//读取服务器的输入流,从这里面可以读取服务器返回的数据
InputStream inputStream = connection.getInputStream();
//输入流包装成BufferReader,方便读取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
//不断读取数据,append到builder中,最后将结果转化为String
String line;
StringBuilder builder = new StringBuilder();
while ((line = reader.readLine()) != null) {
builder.append(line);
}
String string = builder.toString();
Log.i(TAG, "网络访问的结果:" + string);
//关闭连接
connection.disconnect();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
1:声明网络访问权限
<uses-permission android:name="android.permission.INTERNET"/> //网络访问
2:Http明文请求属性设置
从 Android 9.0 (Pie) 开始,默认情况下,应用只能进行 HTTPS 请求。要允许 HTTP 请求,需要在AndroidManifest.xml 中配置网络安全策略
(1)方式一
<application
....
android:networkSecurityConfig="@xml/network_security_config">
....
</application>
然后,创建 res/xml/network_security_config.xml 文件,并定义允许 HTTP 请求的配置:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 允许应用使用明文流量(HTTP) -->
<domain-config cleartextTrafficPermitted="true">
<--表示允许某个域名-->
<domain includeSubdomains="true">titok.fzqq.fun</domain>
</domain-config>
</network-security-config>
(2)方式二:usesCleartextTraffic
或者直接添加全局设置,快速支持HTTP,但这种做法有可能存在安全隐患
usesCleartextTraffic
使用明文网络流量 “cleartext” 指未加密的文本(明文) “traffic” 是网络流量
<application
....
android:usesCleartextTraffic="true">
....
</application>
3:不要在主线程中进行http连接访问
因为http连接是有连接时间和响应时间的,虽然1~2秒(网络不好会更久)对于人的感官来说很短暂,但是对于机器来说度秒如年;所以我们不能再主线程中进行http连接,而要选择去new Thread在子线程做这个事情
总结一下:主线程主要负责 UI 渲染和交互,若在主线程执行耗时操作(如网络请求、文件读写等),会阻塞 UI 刷新,导致界面卡顿甚至 ANR(应用无响应) 。
三:代码中涉及到的写法
访问地址:用的是字符串拼接的方式
archive 英 [ˈɑːkaɪv] 档案 记录
String urlAddress = "http://titok.fzqq.fun/addons/cms/api.user/userInfo?user_id=" + id + "&type=archives";
1:子线程处理http请求
把http代码放到Runnable中,并且用.start()方法启动
2:设置连接属性
涉及到:创建url对象,打开连接,设置连接方法,连接超时时间,读取超时时间
//创建URL对象,传入服务器地址
URL url = new URL(urlAddress);
//打开连接,HttpURLConnection对象中设置一些连接的属性:比如请求方法和连接时间,读取数据的时间
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//连接方法
connection.setRequestMethod("GET");
//连接超时时间
connection.setConnectTimeout(8000);
//读取超时时间
connection.setReadTimeout(80000);
3:如何读取数据
//不断读取数据,append到builder中,最后将结果转化为String
String line;
StringBuilder builder = new StringBuilder();
while ((line = reader.readLine()) != null) {
builder.append(line);
}
String string = builder.toString();
Log.i(TAG, "网络访问的结果:" + string);
//关闭连接
connection.disconnect();
这里的while循环括号中条件代码的写法非常奇妙,好好体会
四:如何发起Http-Post请求
1:总体代码
引子:写完下面这段代码,对客户端和服务器之间怎么进行http连接,能有非常直观的感受;还有一些方法需要熟练,代码中的注释写的非常详细了,下面的说明就简略展开了
/**
* 发起一个post请求
*/
private void SendPostRequest() {
new Thread(new Runnable() {
@Override
public void run() {
//先进行字符串拼接
String loginUrl = "http://titok.fzqq.fun/addons/cms/api.login/login";
try {
/**
* 第一步:构造请求头,包括url,请求方法,发送报文格式,接受数据格式,(可以加连接超时时间,读取数据超时时间)
*/
URL url = new URL(loginUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//设置请求方法
connection.setRequestMethod("POST");
//允许服务器输出数据
connection.setDoOutput(true);
//设置请求头,比如:请求报文格式,要接收的数据格式
connection.setRequestProperty("Content-Type","application/json;charset=uft-8");
connection.setRequestProperty("Accept","application/json");
/**
* 第二步:构造json请求体,用输出流把数据输出
*/
//构造json请求体
String account = edUserName.getText().toString();
String password = edPassword.getText().toString();
String jsonBody = "{ \"account\": \"" + account + "\",\"password\": \"" + password + "\" }";
//搞成输出流,把这段字符串化为json格式
OutputStream os = connection.getOutputStream();
//设置为字节数组方便底层处理
byte[] bytes = jsonBody.getBytes("utf-8");
os.write(bytes,0,jsonBody.length());
/**
* 读取响应
*/
int responseCode = connection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
//200表示访问成功,开始接收返回的数据
InputStream is = connection.getInputStream();
//理解:定义一种读取的方式——带缓冲的字符流读取方式
BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
//把不断读取的相应数据,拼接汇总
String line;
StringBuilder builder = new StringBuilder();
while((line = br.readLine()) != null){
builder.append(line);
}
//得到最终的响应数据了,我们在主线程去使用响应的数据
runOnUiThread(new Runnable() {
@Override
public void run() {
String loginResult = builder.toString();
Log.i(TAG, "run: 返回响应的数据是:" + loginResult);
}
});
}else{
Log.i(TAG, "run: 网络请求失败");
}
} catch (MalformedURLException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
2:构造http请求头
(1)new URL(loginUrl)
注意new URL()这个对象的时候要大写
(2)url.openConnection
通过url打开http连接
(3)setDoOutput
设置参数true;设置允许服务器输出数据
(4)setRequestProperty
设置请求属性;比如说明客户端发送出去的请求的报文格式,要求服务器返回回来的报文格式
property 英 [ˈprɒpəti] 属性
3:构造json请求体,用输出流把数据输出
这里发送的json请求体格式要按照开发文档上的标准来,用参数拼接的方式来整,会轻松很多
(1)getBytes(“utf-8”)
将字符串 jsonBody 按照 UTF-8 字符编码转换为字节数组,再把字节数组输出出去
4:读取响应
(1)getResponseCode
获取响应码,安卓HttpURLConnection中提供了相应的响应码常量,这里的HTTP_OK状态描述就是状态码200
(2)缓冲读取字符
BufferedReader br = new BufferedReader(new InputStreamReader(is,"utf-8"));
这行代码非常精髓,这是一种读取方式,输入流读取数据进来(以utf-8的编码格式)
buffer 英 [ˈbʌfə®] 缓冲区
(3)runOnUiThread
在主线程中处理接收到的响应数据
五:结果
登录成功