【Android】原安卓生态发起网络GET请求 Post请求
三三要成为安卓糕手
引入:在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;@Overrideprotected 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);}@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic 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中,最后将结果转化为StringString 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中,最后将结果转化为StringString 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() {@Overridepublic 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() {@Overridepublic 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
在主线程中处理接收到的响应数据
五:结果
登录成功