You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用Loopj调用GitHub API获取用户信息报错及接口问题

解决GitHub API获取用户name/followers字段的问题

我一眼就看出问题所在啦——你调用的https://api.github.com/users是用户列表接口,它返回的是用户的精简信息集合,只包含login、avatar_url这类基础字段,根本没有name、followers、following这些详细数据!要拿到这些字段,必须对每个用户单独调用详情接口:https://api.github.com/users/{login}(把{login}替换成用户的登录名)。

结合你用的Loopj库,我帮你修改了代码,思路是:先获取用户列表拿到每个用户的login,再逐个请求详情接口补全数据,最后统一更新RecyclerView。

修改后的完整代码

private fun getDataGitDetail() {
    progressBar.visibility = View.VISIBLE
    val client = AsyncHttpClient()
    client.addHeader("Authorization", "token 6fe9dff2e5e43d25eb3abe9ff508a750b972f725")
    client.addHeader("User-Agent", "request")
    val url = "https://api.github.com/users"

    client.get(url, object : AsyncHttpResponseHandler() {
        override fun onSuccess(statusCode: Int, headers: Array<Header>, responseBody: ByteArray) {
            progressBar.visibility = View.INVISIBLE
            val result = String(responseBody)
            Log.d(TAG, result)
            try {
                val jsonArray = JSONArray(result)
                // 计数已完成的详情请求,避免异步请求未结束就更新列表
                var completedRequests = 0
                val totalUsers = jsonArray.length()

                for (i in 0 until jsonArray.length()) {
                    val userListItem = jsonArray.getJSONObject(i)
                    val login = userListItem.getString("login")
                    val avatarUrl = userListItem.getString("avatar_url")

                    // 调用单个用户详情接口
                    val detailUrl = "https://api.github.com/users/$login"
                    client.get(detailUrl, object : AsyncHttpResponseHandler() {
                        override fun onSuccess(
                            detailStatusCode: Int,
                            detailHeaders: Array<Header>,
                            detailResponseBody: ByteArray
                        ) {
                            val detailResult = String(detailResponseBody)
                            val detailJsonObject = JSONObject(detailResult)

                            // 从详情接口提取所需字段,用opt系列方法避免字段不存在报错
                            val name = detailJsonObject.optString("name")
                            val company = detailJsonObject.optString("company")
                            val location = detailJsonObject.optString("location")
                            val followers = detailJsonObject.optInt("followers")
                            val following = detailJsonObject.optInt("following")
                            val repositoryCount = detailJsonObject.optInt("public_repos")

                            // 添加到数据列表,name为空时用login兜底
                            listData.add(
                                Data(
                                    login,
                                    name.takeIf { it.isNotEmpty() } ?: login,
                                    avatarUrl,
                                    company,
                                    location,
                                    repositoryCount,
                                    followers,
                                    following
                                )
                            )

                            // 所有请求完成后更新列表
                            completedRequests++
                            if (completedRequests == totalUsers) {
                                showRecyclerList()
                            }
                        }

                        override fun onFailure(
                            detailStatusCode: Int,
                            detailHeaders: Array<Header>?,
                            detailResponseBody: ByteArray?,
                            error: Throwable
                        ) {
                            // 单个用户请求失败的容错处理,跳过该用户或用默认值
                            Log.e(TAG, "Failed to fetch details for $login", error)
                            completedRequests++
                            if (completedRequests == totalUsers) {
                                showRecyclerList()
                            }
                        }
                    })
                }
            } catch (e: Exception) {
                Toast.makeText(this@MainActivity, e.message, Toast.LENGTH_SHORT).show()
                e.printStackTrace()
            }
        }

        override fun onFailure(
            statusCode: Int,
            headers: Array<Header>,
            responseBody: ByteArray,
            error: Throwable
        ) {
            progressBar.visibility = View.INVISIBLE
            val errorMessage = when (statusCode) {
                401 -> "$statusCode : Unauthorized"
                403 -> "$statusCode : Forbidden"
                404 -> "$statusCode : Not Found"
                else -> "$statusCode : ${error.message}"
            }
            Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show()
        }
    })
}

关键修改点说明

  • 接口切换逻辑:先通过列表接口拿到login,再用login拼接详情接口URL获取完整用户数据
  • 异步请求同步处理:用计数器确保所有详情请求完成后再更新RecyclerView,避免列表显示不全
  • 安全取值:用optString()/optInt()替代getString()/getInt(),防止部分用户未填写字段时抛出异常
  • 容错机制:单个用户详情请求失败时,仍会推进计数并最终更新列表,避免整个流程卡住

内容的提问来源于stack exchange,提问作者Just Lovanto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 17:12:41