睿诚科技协会

Android如何高效获取网络JSON数据?

核心流程

无论使用哪种方法,获取网络 JSON 数据的基本流程都遵循以下步骤:

Android如何高效获取网络JSON数据?-图1
(图片来源网络,侵删)
  1. 添加网络权限:在 AndroidManifest.xml 中声明需要访问网络的权限。
  2. 创建网络请求:指定 URL,使用 HTTP 客户端(如 HttpURLConnection 或第三方库)向服务器发送请求。
  3. 获取响应:读取服务器返回的数据流。
  4. 解析 JSON:使用 JSON 解析库(如 org.json 或 Gson)将字符串数据解析成 Java 对象。
  5. 更新 UI:将解析后的数据在主线程(UI 线程)上展示给用户。

使用 HttpURLConnection (原生 API)

这是最基础的方法,不需要引入第三方库,适合学习网络请求的基本原理。

添加网络权限

app/src/main/AndroidManifest.xml 文件中,在 <application> 标签之前添加:

<uses-permission android:name="android.permission.INTERNET" />

添加网络安全配置 (Android 9.0+)

从 Android 9 (API 28) 开始,默认禁止使用 HTTP 明文传输,如果你的 API 是 http 开头的,需要在 res/xml/network_security_config.xml 中配置:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">your-api-domain.com</domain>
    </domain-config>
</network-security-config>

然后在 AndroidManifest.xml<application> 标签中引用它:

Android如何高效获取网络JSON数据?-图2
(图片来源网络,侵删)
<application
    ...
    android:networkSecurityConfig="@xml/network_security_config"
    ...>
    ...
</application>

提示:对于学习或内部测试,可以直接在 <application> 标签中添加 android:usesCleartextTraffic="true",但这不推荐用于生产环境。

编写网络请求代码

重要:网络操作不能在主线程(UI 线程)中进行,否则会抛出 NetworkOnMainThreadException 异常,我们必须使用异步任务,Thread + HandlerAsyncTask (已废弃)、ExecutorService 或现代的 Kotlin Coroutines/RxJava

这里我们使用 ExecutorService + Handler 的方式,因为它清晰且易于理解。

示例代码:

Android如何高效获取网络JSON数据?-图3
(图片来源网络,侵删)
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final String JSON_URL = "https://api.publicapis.org/random"; // 示例 API
    private TextView textViewResult;
    private ExecutorService executorService;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textViewResult = findViewById(R.id.text_view_result);
        executorService = Executors.newSingleThreadExecutor(); // 创建一个单线程的线程池
        handler = new Handler(Looper.getMainLooper()); // 创建一个与主线程关联的 Handler
        // 在后台线程执行网络请求
        executorService.execute(() -> {
            try {
                String jsonResponse = makeHttpRequest(new URL(JSON_URL));
                // 在主线程更新 UI
                handler.post(() -> {
                    textViewResult.setText(jsonResponse);
                    Toast.makeText(MainActivity.this, "数据加载成功", Toast.LENGTH_SHORT).show();
                });
            } catch (IOException e) {
                Log.e(TAG, "IOException: " + e.getMessage());
                // 在主线程显示错误信息
                handler.post(() -> Toast.makeText(MainActivity.this, "网络请求失败", Toast.LENGTH_SHORT).show());
            }
        });
    }
    private String makeHttpRequest(URL url) throws IOException {
        String jsonResponse = "";
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.setConnectTimeout(15000); // 15秒连接超时
            urlConnection.setReadTimeout(15000);   // 15秒读取超时
            urlConnection.connect();
            if (urlConnection.getResponseCode() == 200) { // HTTP 200 OK
                inputStream = urlConnection.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuilder buffer = new StringBuilder();
                String line;
                while ((line = reader.readLine()) != null) {
                    buffer.append(line).append("\n");
                }
                jsonResponse = buffer.toString();
            } else {
                Log.e(TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(TAG, "IOException: " + e.getMessage());
        } finally {
            // 确保流和连接被关闭
            if (reader != null) reader.close();
            if (inputStream != null) inputStream.close();
            if (urlConnection != null) urlConnection.disconnect();
        }
        return jsonResponse;
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 关闭线程池,防止内存泄漏
        executorService.shutdown();
    }
}

使用现代库 (推荐)

原生 HttpURLConnection 代码冗长且容易出错,在现代 Android 开发中,我们强烈推荐使用第三方库来简化网络请求。

方案 A:Retrofit + Gson (Java/Kotlin)

这是目前最流行、最强大的组合,Retrofit 负责处理网络请求,Gson 负责解析 JSON。

添加依赖

app/build.gradle 文件中添加:

dependencies {
    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Gson 转换器
    // OkHttp (Retrofit 的默认依赖)
    implementation 'com.squareup.okhttp3:okhttp:4.9.3'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' // 用于打印日志
}

添加网络权限和配置 (与方法一相同)

创建数据模型

根据你的 JSON 结构创建 Java/Kotlin 类。

示例 JSON:

{
  "count": 1,
  "entries": [
    {
      "API": "Yes or No",
      "Description": "Get a random yes/no answer to a question",
      "Auth": "No",
      "HTTPS": true,
      "Cors": "unknown",
      "Link": "https://yesno.wtf/api",
      "Category": "Development"
    }
  ]
}

Java 数据模型:

// Entry.java
public class Entry {
    public String API;
    public String Description;
    public String Auth;
    public boolean HTTPS;
    public String Cors;
    public String Link;
    public String Category;
}
// RandomApi.java
public class RandomApi {
    public int count;
    public List<Entry> entries;
}

创建 Retrofit 接口

定义你的 API 端点。

import retrofit2.Call;
import retrofit2.http.GET;
public interface ApiService {
    @GET("random") // API 的路径
    Call<RandomApi> getRandomData();
}

执行请求并更新 UI

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity {
    private TextView textViewResult;
    private ApiService apiService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textViewResult = findViewById(R.id.text_view_result);
        // 1. 创建 Retrofit 实例
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.publicapis.org/") // API 的基础 URL
                .addConverterFactory(GsonConverterFactory.create()) // 添加 Gson 转换器
                .build();
        // 2. 创建 API 接口的实例
        apiService = retrofit.create(ApiService.class);
        // 3. 发起异步请求
        apiService.getRandomData().enqueue(new Callback<RandomApi>() {
            @Override
            public void onResponse(Call<RandomApi> call, Response<RandomApi> response) {
                if (response.isSuccessful() && response.body() != null) {
                    RandomApi randomApi = response.body();
                    List<Entry> entries = randomApi.entries;
                    if (!entries
分享:
扫描分享到社交APP
上一篇
下一篇