网络权限

无论使用哪种方式,第一步都是在 AndroidManifest.xml 文件中声明网络权限,没有这个权限,你的应用将无法访问网络。

android api连互联网
(图片来源网络,侵删)
<!-- 允许应用打开网络套接字 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 如果你的应用需要使用明文HTTP(不推荐),还需要添加这个权限 -->
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
<!-- 对于 Android 9 (API 28) 及以上,允许使用明文HTTP -->
<!-- <application
    ...
    android:usesCleartextTraffic="true"
    ...> -->

使用 HttpURLConnection (传统方式)

这是 Java 标准库中自带的 HTTP 客户端,简单、无需额外依赖,但功能相对基础。

基本使用示例 (GET 请求)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class NetworkUtil {
    public static String getResponseFromHttpUrl(URL url) throws IOException {
        HttpURLConnection urlConnection = null;
        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            // 设置请求方法
            urlConnection.setRequestMethod("GET");
            // 获取输入流
            InputStream in = urlConnection.getInputStream();
            // 读取输入流内容
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        } finally {
            // 确保连接被关闭
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
    }
}

特点:

  • 优点: 内置于 Android 系统,无需引入第三方库。
  • 缺点: API 较为底层,需要手动处理线程、输入流、连接关闭等,代码冗长。

使用现代网络库 (强烈推荐)

手动管理网络连接非常繁琐,且容易出错,现代 Android 开发强烈推荐使用第三方库来简化网络操作,它们能自动处理线程、JSON 解析、错误处理等。

Retrofit (首选)

Retrofit 是一个类型安全的 HTTP 客户端,由 Square 公司开发,它是目前 Android 开发中最流行、最强大的网络库,它通常与 OkHttp (作为其默认的 HTTP 客户端) 和 Gson (用于 JSON 解析) 一起使用。

android api连互联网
(图片来源网络,侵删)

第一步:添加依赖

app/build.gradle 文件中添加:

// OkHttp (Retrofit 的默认依赖)
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Gson Converter (用于将 JSON 响应自动转换为 Java/Kotlin 对象)
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// 协程支持 (Kotlin)
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'

第二步:定义数据模型

根据 API 返回的 JSON 数据创建对应的 Kotlin/Java 数据类。

android api连互联网
(图片来源网络,侵删)
// data.kt
data class User(
    val id: Int,
    val name: String,
    val username: String,
    val email: String
)

第三步:创建 Retrofit 接口

定义一个接口,描述你的 API 请求。

import retrofit2.http.GET
import retrofit2.http.Path
interface ApiService {
    // GET https://jsonplaceholder.typicode.com/users/1
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: Int): User // 使用 suspend 函数支持协程
}

第四步:创建 Retrofit 实例并发起请求

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object RetrofitClient {
    private const val BASE_URL = "https://jsonplaceholder.typicode.com/"
    val instance: ApiService by lazy {
        val retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        retrofit.create(ApiService::class.java)
    }
}
// 在 ViewModel 或 Activity/Fragment 中使用
// 假设在 ViewModel 中
class MyViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    fun fetchUser() {
        viewModelScope.launch { // 使用协程确保在主线程更新 UI
            try {
                val fetchedUser = RetrofitClient.instance.getUser(1)
                _user.postValue(fetchedUser)
            } catch (e: Exception) {
                // 处理错误
                Log.e("MyViewModel", "Error fetching user", e)
            }
        }
    }
}

特点:

  • 优点: 代码极其简洁、类型安全、支持协程/回调、可插拔的转换器(支持 JSON、XML、Protobuf 等)、强大的拦截器功能。
  • 缺点: 需要引入第三方库。

Volley

Volley 是 Google 推荐的一个网络库,特别适合数据量不大、但需要频繁进行网络通信的场景(如加载图片、JSON 数据)。

第一步:添加依赖

app/build.gradle 文件中添加:

implementation 'com.android.volley:volley:1.2.1'

第二步:发起请求

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
// 在 Activity 或其他地方
public class MainActivity extends AppCompatActivity {
    private RequestQueue queue;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        queue = Volley.newRequestQueue(this);
        jsonCall();
    }
    private void jsonCall() {
        String url = "https://jsonplaceholder.typicode.com/users/1";
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest
                (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        // 处理成功响应
                        Log.d("Volley", response.toString());
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        // 处理错误
                        Log.e("Volley", "Error: " + error.getMessage());
                    }
                });
        // 将请求添加到队列中
        queue.add(jsonObjectRequest);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 取消所有请求,防止内存泄漏
        queue.cancelAll("MyTag");
    }
}

特点:

  • 优点: 内置图片加载功能 (NetworkImageView)、请求优先级管理、自动缓存、代码比 HttpURLConnection 简单。
  • 缺点: 对于大文件下载(如视频)性能不佳,社区活跃度不如 Retrofit。

使用 Jetpack DataStore (现代数据存储)

虽然 DataStore 本身不是网络库,但它与网络库配合使用,是现代 Android 应用的标准架构,当你从网络获取数据后,通常会将其存储在 DataStore 中,以便在没有网络时或下次启动应用时使用。

// 1. 定义 Proto 数据类 (使用 Proto DataStore)
// user.proto
syntax = "proto3";
option java_package = "com.example.myapp.data";
option java_multiple_files = true;
message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}
// 2. 在 ViewModel 中结合使用
class MyViewModel @ViewModelInject constructor(
    private val apiService: ApiService,
    private val userPreferencesProtoDataStore: UserPreferencesProtoDataStore // 假设已配置好
) : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    fun loadUser() {
        viewModelScope.launch {
            // 1. 首先尝试从 DataStore 读取缓存
            val cachedUser = userPreferencesProtoDataStore.getUser()
            if (cachedUser != null) {
                _user.postValue(cachedUser)
            }
            // 2. 然后从网络获取最新数据
            try {
                val freshUser = apiService.getUser(1)
                _user.postValue(freshUser)
                // 3. 将新数据存入 DataStore
                userPreferencesProtoDataStore.saveUser(freshUser)
            } catch (e: Exception) {
                // 网络错误,如果已经有缓存,可以不处理或提示用户
                if (cachedUser == null) {
                    // 没有缓存,网络也失败,需要处理错误
                    Log.e("MyViewModel", "