贝博恩创新科技网

Android Internet教程从哪开始学?

Android 网络编程全面教程

本教程将带你从零开始,学习如何在 Android 应用中进行网络请求,并最终掌握业界标准的现代网络解决方案。

Android Internet教程从哪开始学?-图1
(图片来源网络,侵删)

目录

  1. 第一部分:基础准备

    • 1 网络权限
    • 2 主线程与子线程(UI 线程)
    • 3 添加网络依赖库
  2. 第二部分:经典方式 - HttpURLConnection

    • 1 基本使用(GET 请求)
    • 2 POST 请求与参数传递
    • 3 优缺点分析
  3. 第三部分:现代方式 - Retrofit + OkHttp

    • 1 为什么选择 Retrofit?(优点)
    • 2 搭建 Retrofit 环境
    • 3 定义 API 接口
    • 4 发起同步和异步请求
    • 5 处理响应数据(JSON 解析)
    • 6 完整示例:获取并显示 GitHub 用户列表
  4. 第四部分:进阶主题

    Android Internet教程从哪开始学?-图2
    (图片来源网络,侵删)
    • 1 图片加载库:Glide / Picasso
    • 2 数据持久化:Room + Retrofit(MVVM 架构)
    • 3 网络状态监听
  5. 第五部分:最佳实践与总结


第一部分:基础准备

在学习网络请求之前,必须了解几个基本概念。

1 网络权限

你的应用需要明确告知系统它需要访问互联网,在 AndroidManifest.xml 文件中添加 <uses-permission>

<!-- 在 <manifest> 标签内部添加 -->
<uses-permission android:name="android.permission.INTERNET" />

注意:从 Android 9 (API 28) 开始,默认情况下,应用只能使用 HTTPS,如果你的 API 服务器只有 HTTP,需要在 application 标签下添加 android:usesCleartextTraffic="true"

<application
    ...
    android:usesCleartextTraffic="true">
    ...
</application>

2 主线程与子线程(UI 线程)

Android 的 UI 操作(如更新 TextView、显示 Toast)必须在主线程(UI 线程)中执行,而网络请求是一个耗时操作,如果在主线程中进行,会导致应用无响应,甚至出现ANR (Application Not Responding) 错误。

Android Internet教程从哪开始学?-图3
(图片来源网络,侵删)

解决方案:所有网络请求都必须在子线程(后台线程)中执行。

3 添加网络依赖库

现代 Android 开发强烈推荐使用第三方库来简化网络操作,我们将使用以下组合:

  • Retrofit: 用于处理网络请求的接口定义和转换。
  • OkHttp: 一个高效的 HTTP 客户端,Retrofit 底层默认使用它。
  • Gson: 用于将 JSON 字符串自动转换为 Java/Kotlin 对象。
  • Glide: 用于高效加载和显示网络图片。

app/build.gradle.kts (或 app/build.gradle) 文件中添加依赖:

// build.gradle.kts (Kotlin DSL)
dependencies {
    // Retrofit: 核心库
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    // Gson: JSON 转换器
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    // OkHttp: 日志拦截器,方便调试
    implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
    // Glide: 图片加载库
    implementation("com.github.bumptech.glide:glide:4.16.0")
    kapt "com.github.bumptech.glide:compiler:4.16.0" // 如果使用 Kotlin,需要添加 kapt
}

第二部分:经典方式 - HttpURLConnection

这是 Android SDK 自带的网络 API,无需额外依赖,了解它有助于理解网络请求的本质。

1 基本使用(GET 请求)

// 在子线程中执行
thread {
    val url = URL("https://api.github.com/users/octocat")
    val connection = url.openConnection() as HttpURLConnection
    connection.requestMethod = "GET"
    try {
        val responseCode = connection.responseCode
        if (responseCode == HttpURLConnection.HTTP_OK) {
            val inputStream = connection.inputStream
            val response = inputStream.bufferedReader().use { it.readText() }
            // response 就是服务器返回的 JSON 字符串
            Log.d("HttpURLConnection", response)
        } else {
            Log.e("HttpURLConnection", "GET request failed with code: $responseCode")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        connection.disconnect()
    }
}

2 POST 请求与参数传递

POST 请求需要将参数放在请求体中。

thread {
    val url = URL("https://example.com/api/login")
    val connection = url.openConnection() as HttpURLConnection
    connection.requestMethod = "POST"
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
    connection.doOutput = true // 允许输出
    val postData = "username=test&password=123456"
    val outputStream = connection.outputStream
    outputStream.write(postData.toByteArray())
    outputStream.flush()
    // ... 后续处理响应代码和输入流,与 GET 类似 ...
    outputStream.close()
}

3 优缺点分析

  • 优点

    无需额外依赖,是 Android SDK 的一部分。

  • 缺点
    • API 繁琐,需要手动管理流、线程和异常。
    • 处理 JSON 等数据需要手动解析。
    • 代码冗长,可读性差。

在现代开发中,除非有特殊限制,否则不推荐直接使用 HttpURLConnection


第三部分:现代方式 - Retrofit + OkHttp

这是目前 Android 网络编程的事实标准,它极大地简化了网络请求的代码。

1 为什么选择 Retrofit?

  • 声明式 API:通过一个简单的接口定义你的 API,Retrofit 会帮你实现它。
  • 简洁的代码:消除了 HttpURLConnection 的样板代码。
  • 强大的功能:支持同步/异步请求、拦截器、转换器等。
  • 基于 OkHttp:自动利用 OkHttp 的高性能和连接池。

2 搭建 Retrofit 环境

请参考第一部分 3 添加 Retrofit, OkHttp, Gson 的依赖。

3 定义 API 接口

这是 Retrofit 的核心,创建一个接口,用注解来描述 API 的信息。

import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
interface GitHubApiService {
    // GET 请求,路径是 "users/{user}"
    // {user} 是一个路径参数
    @GET("users/{user}")
    fun getUser(@Path("user") username: String): Call<User>
    // GET 请求,路径是 "users"
    @GET("users")
    fun getUsers(): Call<List<User>>
}

4 发起同步和异步请求

创建 Retrofit 实例:

object RetrofitClient {
    private const val BASE_URL = "https://api.github.com/"
    val instance: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create()) // 添加 Gson 转换器
            .build()
    }
}

异步请求(推荐)

val apiService = RetrofitClient.instance.create(GitHubApiService::class.java)
// 发起异步 GET 请求
apiService.getUser("google").enqueue(object : Callback<User> {
    override fun onResponse(call: Call<User>, response: Response<User>) {
        if (response.isSuccessful) {
            // 请求成功
            val user = response.body()
            Log.d("Retrofit", "User: ${user?.login}, Name: ${user?.name}")
            // 在主线程更新 UI
            runOnUiThread {
                //  tvUserName.text = user?.name
            }
        } else {
            // 服务器返回错误,如 404, 500 等
            Log.e("Retrofit", "Error: ${response.code()}")
        }
    }
    override fun onFailure(call: Call<User>, t: Throwable) {
        // 网络连接失败或解析失败
        Log.e("Retrofit", "Failure: ${t.message}")
    }
})

同步请求

// 注意:同步请求必须在子线程中调用,否则会阻塞主线程
thread {
    try {
        val response = apiService.getUser("jetbrains").execute()
        if (response.isSuccessful) {
            val user = response.body()
            Log.d("Retrofit", "Sync User: ${user?.login}")
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

5 处理响应数据(JSON 解析)

Retrofit + Gson 可以自动将 JSON 响应体转换成我们定义的 Kotlin 数据类。

定义数据类

// data class 对应 JSON 的结构
data class User(
    val login: String,
    val id: Int,
    val avatar_url: String,
    val name: String?,
    val public_repos: Int
)

Retrofit 自动转换

当你调用 response.body() 时,Gson 会自动将类似以下的 JSON 字符串:

{
  "login": "google",
  "id": 1,
  "avatar_url": "https://avatars.githubusercontent.com/u/1?v=4",
  "name": "Google",
  "public_repos": 50
}

转换成 User 对象。

6 完整示例:获取并显示 GitHub 用户列表

布局文件 activity_main.xml:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rvUsers"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

数据类 User.kt:

data class User(val login: String, val avatar_url: String)

UserAdapter.kt (RecyclerView 适配器):

class UserAdapter(private val users: List<User>) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
    class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val ivAvatar: ImageView = itemView.findViewById(R.id.ivAvatar)
        val tvLogin: TextView = itemView.findViewById(R.id.tvLogin)
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view)
    }
    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        val user = users[position]
        holder.tvLogin.text = user.login
        // 使用 Glide 加载图片
        Glide.with(holder.itemView.context)
            .load(user.avatar_url)
            .into(holder.ivAvatar)
    }
    override fun getItemCount() = users.size
}

(需要创建 item_user.xml 布局,包含一个 ImageView 和一个 TextView)

MainActivity.kt:

class MainActivity : AppCompatActivity() {
    private lateinit var apiService: GitHubApiService
    private lateinit var adapter: UserAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val rvUsers = findViewById<RecyclerView>(R.id.rvUsers)
        rvUsers.layoutManager = LinearLayoutManager(this)
        adapter = UserAdapter(emptyList())
        rvUsers.adapter = adapter
        // 初始化 Retrofit
        apiService = RetrofitClient.instance.create(GitHubApiService::class.java)
        // 发起请求
        fetchUsers()
    }
    private fun fetchUsers() {
        apiService.getUsers().enqueue(object : Callback<List<User>> {
            override fun onResponse(call: Call<List<User>>, response: Response<List<User>>) {
                if (response.isSuccessful) {
                    response.body()?.let { users ->
                        // 更新 UI
                        adapter.updateUsers(users) // 假设你给 adapter 添加了 updateUsers 方法
                    }
                }
            }
            override fun onFailure(call: Call<List<User>>, t: Throwable) {
                Log.e("MainActivity", "Failed to fetch users: ${t.message}")
            }
        })
    }
}

第四部分:进阶主题

1 图片加载库:Glide / Picasso

网络图片加载是一个复杂的问题(缓存、缩放、生命周期管理等),强烈推荐使用成熟的库。

Glide 使用示例

// 在 Activity/Fragment 中加载图片
Glide.with(this) // 上下文
    .load("https://example.com/image.jpg") // 图片 URL
    .into(imageView) // 目标 ImageView

2 数据持久化:Room + Retrofit(MVVM 架构)

一个好的应用不会每次都从网络获取数据,通常的流程是:

  1. 先查本地数据库 (Room)
  2. 如果有且未过期,直接显示本地数据。
  3. 如果没有或已过期,再发网络请求 (Retrofit)。
  4. 将网络请求到的数据存入数据库,并更新 UI。

这构成了一个典型的 MVVM (Model-View-ViewModel) 架构,

  • Model: Room 数据库 + Retrofit API。
  • View: Activity/Fragment + XML 布局。
  • ViewModel: 负责协调 Model 和 View,处理业务逻辑。

3 网络状态监听

可以使用 ConnectivityManagerNetworkCapabilities 来监听网络状态的变化(如从 Wi-Fi 切换到移动数据)。

val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
val hasInternet = capabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) == true

第五部分:最佳实践与总结

  1. 永远不要在主线程进行网络请求:使用 thread, AsyncTask (已废弃), ExecutorService, 或者协程 (Coroutines)。
  2. 使用现代库:优先选择 Retrofit + OkHttp 的组合,它们是行业标准,经过充分测试,能极大提高开发效率和代码质量。
  3. 处理错误:总是检查 response.isSuccessful,并妥善处理 onFailure 回调中的网络异常和服务器错误。
  4. 数据解析:使用 Gson 或 Moshi 等转换器来自动处理 JSON,避免手动解析字符串。
  5. 图片加载:使用 Glide 或 Picasso 等专业库来加载网络图片,不要自己写。
  6. 考虑架构:在复杂应用中,采用 MVVM 或 MVI 架构,将网络请求、数据存储和 UI 分离,使代码更清晰、更易于维护。
  7. 安全性:优先使用 HTTPS,处理敏感数据时,考虑使用 Token 认证等安全机制。

希望这份教程能帮助你顺利掌握 Android 网络编程!祝你编码愉快!

分享:
扫描分享到社交APP
上一篇
下一篇