Java http请求及常见数据交互格式处理

在android项目的开发过程中网络请求是非常常用的。这里简单介绍两种方法

在android中无论使用哪种方法发起网络请求,都需要先声明网络权限

1
2
3
4
5
6
<!-- .AndroidManifests.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.moshuying">
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

http请求

通常在android项目中会使用两种(也有可能基于这两种进行封装)请求方式,HttpURLConnection是google较为推荐的一种。okhttp也不错,往往能正确获取到页面数据。

HttpURLConnection

作为官方推荐的一种请求方法,自然是不需要引入的啦~

非常简单直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

public class MainActivity extends AppCompatActivity {

private TextView textView;

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

findViewById(R.id.send_request).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send();
}
});

textView = (TextView) findViewById(R.id.response_data);
}

private void send() {
//开启线程,发送请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL("http://www.163.com");
connection = (HttpURLConnection) url.openConnection();
//设置请求方法
connection.setRequestMethod("GET");
//设置连接超时时间(毫秒)
connection.setConnectTimeout(5000);
//设置读取超时时间(毫秒)
connection.setReadTimeout(5000);

//返回输入流
InputStream in = connection.getInputStream();

//读取输入流
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
show(result.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {//关闭连接
connection.disconnect();
}
}
}
}).start();
}

private void show(final String result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(result);
}
});
}
}

因为在 Android 中不允许在子线程中执行 UI 操作(当然不光是Android,python js(worker)都不允许在子线程执行ui操作),所以我们通过 runOnUiThread 方法,切换为主线程,然后再更新 UI 元素。

关于不能在子线程执行UI操作的主要原因是线程安全,实际上并不是禁止在子线程中执行 UI 操作而是禁止在非UI线程执行UI 操作。

绝大部分 GUI 系统都是只允许「单个线程对某块区域做绘制操作的」,例如在 Windows 和 Android 系统下都把这块区域叫做 Window。如果允许多个线程对同一块区域做绘制的话,很有可能导致某个线程还没绘制完,另一个线程上一些依赖之前绘制结果的操作出问题,例如 Alpha 混合。除非加锁,然而加锁更慢还不如单线程。[ 1]nekocode.Android[ DB].知乎,https://www.zhihu.com/question/24764972/answer/272848960

okhttp

OKHttp 是一个处理网络请求的开源项目,目前是 Android 最火热的轻量级框架,由移动支付 Square 公司贡献(该公司还贡献了Picasso)。希望替代 HttpUrlConnection 和 Apache HttpClient。[ 2]deniro.说说在 Android 中如何发送 HTTP 请求[ DB].简书,https://www.jianshu.com/p/5eee1ef02700

这个库不是内置的,需要先引入依赖,最新版本和具体文档在OkHttp中获取。然后在项目目录下的build.gradle(Module:app)文件中更新依赖,看清楚文件名别弄错了

我这里用的是android 10.0+ 所以没有compile 变成了implementation

1
2
3
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
}

然后记得点击右上角的Sync now把依赖文件同步后真正加进来

这里简单做了一个get请求和一个post请求的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class HttpGetRequest implements Callable<String> {
public String url = null;
@Override
public String call() {
String returnValue = null;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Response response = null;
try {
response = client.newCall(request).execute();//发送请求
returnValue = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return returnValue;
}
}

class HttpPostRequest implements Callable<String>{
public String url = null;
public String json = null;
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
@Override
public String call(){
String returnValue = null;
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder().url(url).post(body).build();
Response response = null;
try {
response = client.newCall(request).execute();
returnValue = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return returnValue;
}
}

考虑到使用时需要用到多线程操作,为了避免因为请求时间造成的界面卡顿,这里用了Callable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static String sendByOKHttp() {
ExecutorService executorService = Executors.newCachedThreadPool();
HttpGetRequest httpGetRequest = new HttpGetRequest();
httpGetRequest.url = "https://exampleapp.moshuying.top/node_api/product_list";
Future<String> submit = executorService.submit(httpGetRequest);
String data = "";
try {
data = submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(data);
LinkedHashMap<String,String> jsonMap = JSON.parseObject(data,new TypeReference<LinkedHashMap<String, String>>(){});
return jsonMap.get("data");
}

参考文章:
说说在 Android 中如何发送 HTTP 请求
OkHttp