Skip to content

网络编程

网络配置前置要求

进行任何网络编程前,必须在 AndroidManifest.xml 中配置权限和流量设置:

  • 申请网络权限:

    <application>同级。

    <uses-permission android:name="android.permission.INTERNET" />
    
  • Android 9.0 及以上版本默认禁止明文(HTTP)网络传输,若要支持 HTTP 请求,需在 <application> 标签中添加:
    android:usesCleartextTraffic="true"
    

WebView 组件

用于在应用程序内部直接展示网页的控件。

  • 基本加载
    WebView webView = findViewById(R.id.webView);
    webView.loadUrl("http://www.baidu.com");
    
  • 允许执行 JavaScript(许多网页依赖 JS):
    webView.getSettings().setJavaScriptEnabled(true);
    
  • 在当前 WebView 中打开链接(防止跳转到系统浏览器):
    webView.setWebViewClient(new WebViewClient());
    

Handler 异步通信

应用启动时默认开启一个主线程(UI线程)。

为了不阻塞UI线程的正常运行,我们需要将一些耗时操作(如联网下载文件)放在子线程中进行操作,操作完成后若需要更新UI,不能直接在子线程中进行(因为UI操作只能在UI线程中进行),所以需要通过Handler来进行UI线程和子线程间的通信。

子线程中无法修改主线程的内容,只能将值传递给主线程

Handler常用方法

  • handleMessage(Message msg)

    在主类中重写,以实现接收到消息后的处理。

    不需要显式调用,会自动触发。

  • sendEmptyMessage(int what)

    在子线程中调用,用于发回空信息,用于在只需要发送一个整形时的信息。

  • sendMessage(Message msg)

    子线程中调用,发送消息对象msg。

Message类常用属性

  • arg1 :int类型,存放整型数据
  • obj:Object类型,存放发送给消息接收者的任意类型的数据
  • arg2:int类型,存放整型数据
  • what:int类型,存放用户自定义的消息

HttpURLConnection

原生提供的网络请求 API,用于发送 HTTP 请求并获取响应。注意:网络请求属于耗时操作,必须在子线程(后台线程)中执行,否则会导致 ANR。

标准使用步骤:

new Thread(new Runnable() {
    @Override
    public void run() {
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        try {
            // 1. 创建 URL 对象并打开连接
            URL url = new URL("http://www.baidu.com");
            connection = (HttpURLConnection) url.openConnection();

            // 2. 设置请求方式和超时时间
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);

            // 3. 获取输入流并读取数据
            InputStream in = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }

            // (处理 response 数据...)

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 4. 关闭流和连接
            if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } }
            if (connection != null) { connection.disconnect(); }
        }
    }
}).start();

线程与 UI 更新

Android 的 UI 是线程不安全的,不允许在子线程中直接修改 UI 控件(例如 TextView.setText())。

必须借助 runOnUiThread() 方法将更新 UI 的操作切换回主线程:

1
2
3
4
5
6
7
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // 在这里进行 UI 更新操作
        textView.setText(responseData);
    }
});

响应状态码

  • 200:成功
  • 403
  • 404
  • 500
  • 502
  • 503

OkHttp 网络库

OkHttp 是由 Square 公司开发的优秀第三方网络库,替代了原生繁琐的 API。

  • 引入依赖: 在 build.gradle (app) 的 dependencies 中添加:
    implementation 'com.squareup.okhttp3:okhttp:4.1.0'
    

GET 请求

1
2
3
4
5
6
7
8
// 同样需要放在子线程中执行
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url("http://www.baidu.com")
        .build();
// 同步执行请求
Response response = client.newCall(request).execute();
String responseData = response.body().string();

POST 请求

POST 请求需要先构建 RequestBody 来存放提交的数据:

OkHttpClient client = new OkHttpClient();
// 构建请求体
RequestBody requestBody = new FormBody.Builder()
        .add("username", "admin")
        .add("password", "123456")
        .build();
// 发送 POST 请求
Request request = new Request.Builder()
        .url("http://www.example.com/login")
        .post(requestBody)
        .build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();

JSON 解析 (GSON)

JSON 是一种轻量级的数据交换格式,GSON 是 Google 提供的开源解析库,可以方便地将 JSON 数据映射为 Java 对象。

  • 引入依赖
    implementation 'com.google.code.gson:gson:2.8.5'
    
  • 第一步:定义实体类 (Java Bean) 类中的属性名需要与 JSON 数据中的键(key)保持一致。
  • 第二步:解析 JSON 字符串

    - 解析单个对象

    1
    2
    3
    4
      ```java
      Gson gson = new Gson();
      App app = gson.fromJson(jsonData, App.class);
      ```
    

    - 解析 JSON 数组 (包含多个对象)

    1
    2
    3
    4
    5
    6
    7
    8
      ```java
      Gson gson = new Gson();
      // 借助 TypeToken 获取泛型集合类型
      List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>(){}.getType());
      for (App app : appList) {
          // 遍历处理每个对象
      }
      ```