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

Android应用无法读取服务器JSON文件问题求助

无法读取Dreamhost服务器JSON文件的问题排查与解决

我的应用距离发布到Android Play Store只剩最后一步,但遇到了关键问题:用Kotlin开发的Android应用无法读取Dreamhost服务器上的JSON文件,文件地址为https://apis.androidparadise.site/contacts/Contacts.json。当前主Activity中when语句的event变量始终返回ContactsViewModel.RecipientLoadingEvent.Failure,仅显示失败提示Toast,且无法获取ViewModel返回的错误信息,推测JSON读取/上传逻辑存在问题,需要排查解决。


现有代码实现

数据类定义

data class ContactResponseItem(
    val comment: String?,
    @SerializedName("data")
    val dataList: List<Data?>,
    val database: String?,
    val name: String?,
    val type: String?,
    val version: String?
)

API接口

interface ContactApi {
    @GET("/contacts/Contacts.json")
    suspend fun getAllContacts() : Response<List<ContactResponseItem>>
    @POST("/contacts/new")
    suspend fun addContact(@Body contact:ContactResponseItem): Response<ContactResponseItem>
}  

仓库接口与实现类

interface ContactsRepository {
    suspend fun getAllContacts(): Resource<List<ContactResponseItem>>
    suspend fun addContact(contact: ContactResponseItem): Resource<ContactResponseItem>
}   
class ContactsRepositoryImpl @Inject constructor(private val api: ContactApi): ContactsRepository {
    override suspend fun getAllContacts(): Resource<List<ContactResponseItem>> {
        return try {
            val response = api.getAllContacts()
            val result = response.body()

            if (response.isSuccessful && result != null) {
                Resource.Success(result)
            } else {
                Resource.Error("Response was not successful")
            }
        } catch (e: Exception) {
            Resource.Error(e.message ?: "Failed to retrieve contacts")
        }
    }

    override suspend fun addContact(contact: ContactResponseItem): Resource<ContactResponseItem> {
        return try {
            val response = api.addContact(contact)
            val result = response.body()

            Log.d("ContactsRepositoryImpl", response.isSuccessful.toString())
            Log.d("ContactRepositoryImpl", (result != null).toString())
            if (response.isSuccessful && result != null) {
                Resource.Success(result)
            } else {
                Resource.Error("Response was not successful")
            }
        } catch (e: Exception) {
            Resource.Error(e.message ?: "Failed to retrieve contacts")
        }
    }
}

ViewModel中的方法

fun getContactEmails(): MutableList<String> {
    viewModelScope.launch(dispatchers!!.io) {
        when (val loadResponse = contactsRepo.getAllContacts()) {
            is Resource.Success -> {
                for(i in 0..loadResponse.data?.size!!){
                    if (loadResponse.data[i].name == "data") {
                        val dataLoad = loadResponse.data[i].dataList[0]
                        dataLoad?.let { emailList.add(it.email) }
                    }
                }
                _recipientload.value = RecipientLoadingEvent.Success("The first email found: ${emailList[0]}")
            }
            is Resource.Error<*> -> RecipientLoadingEvent.Failure("Couldn't load client's emails")
            else -> _recipientload.value = RecipientLoadingEvent.Failure(loadResponse.errorMsg.toString())
        }
    }
    return emailList
}

主Activity中的代码

contactsVM.recipientLoad.collect { event ->
    when (event) {
        is ContactsViewModel.RecipientLoadingEvent.Success -> {
            Toast.makeText(this@CreateNewUserRegistration, contactsVM.getContactEmails()[0], Toast.LENGTH_SHORT).show()
        }
        is ContactsViewModel.RecipientLoadingEvent.Failure -> {
            Toast.makeText(
                this@CreateNewUserRegistration,
                "Failed to retrieve email",
                Toast.LENGTH_LONG
            ).show()
            Toast.makeText(
                this@CreateNewUserRegistration,
                "Failed to send data to server",
                Toast.LENGTH_SHORT
            ).show()
        }
        else -> {}
    }
}

问题排查点

  1. API接口与JSON结构不匹配:若服务器返回的是单个ContactResponseItem对象,但接口定义为返回List<ContactResponseItem>,会直接导致解析失败。
  2. ViewModel循环越界:for(i in 0..loadResponse.data?.size!!)使用闭区间,会触发IndexOutOfBoundsException,因为列表索引是从0到size-1。
  3. 错误事件未发送:ViewModel中Resource.Error分支仅创建了Failure事件,但未赋值给_recipientload.value,Activity无法收到错误信息。
  4. Activity重复发起请求:Success分支再次调用getContactEmails(),会重新触发网络请求,且此时emailList可能未完成填充,导致异常。
  5. 仓库层错误信息缺失:仅返回固定文本,未提取服务器返回的具体错误内容,无法定位问题根源。

解决方案

1. 修正API接口与JSON结构匹配

先确认服务器返回的JSON结构:如果是单个对象而非列表,修改API接口:

interface ContactApi {
    @GET("/contacts/Contacts.json")
    suspend fun getAllContacts() : Response<ContactResponseItem> // 改为单个对象
    @POST("/contacts/new")
    suspend fun addContact(@Body contact:ContactResponseItem): Response<ContactResponseItem>
}  

同步修改仓库和ViewModel的泛型类型,比如Resource<ContactResponseItem>,后续逻辑也对应调整为处理单个对象。

2. 修复ViewModel循环与事件发送

fun getContactEmails(): MutableList<String> {
    viewModelScope.launch(dispatchers!!.io) {
        when (val loadResponse = contactsRepo.getAllContacts()) {
            is Resource.Success -> {
                val responseData = loadResponse.data ?: run {
                    _recipientload.value = RecipientLoadingEvent.Failure("数据为空")
                    return@launch
                }
                // 修正循环逻辑,处理单个对象
                if (responseData.name == "data") {
                    responseData.dataList.forEach { data ->
                        data?.email?.let { emailList.add(it) }
                    }
                }
                // 确保有数据再发送成功事件
                if (emailList.isNotEmpty()) {
                    _recipientload.value = RecipientLoadingEvent.Success("找到第一个邮箱: ${emailList[0]}")
                } else {
                    _recipientload.value = RecipientLoadingEvent.Failure("未找到邮箱数据")
                }
            }
            is Resource.Error<*> -> {
                // 正确发送错误事件
                _recipientload.value = RecipientLoadingEvent.Failure(loadResponse.errorMsg ?: "加载联系人失败")
            }
            else -> {
                _recipientload.value = RecipientLoadingEvent.Failure("未知错误")
            }
        }
    }
    return emailList
}

3. 修复Activity重复调用问题

contactsVM.recipientLoad.collect { event ->
    when (event) {
        is ContactsViewModel.RecipientLoadingEvent.Success -> {
            // 直接使用事件携带的消息,避免重复请求
            Toast.makeText(this@CreateNewUserRegistration, event.message, Toast.LENGTH_SHORT).show()
        }
        is ContactsViewModel.RecipientLoadingEvent.Failure -> {
            // 显示具体错误信息
            Toast.makeText(
                this@CreateNewUserRegistration,
                event.message,
                Toast.LENGTH_LONG
            ).show()
        }
        else -> {}
    }
}

4. 优化仓库层错误处理

override suspend fun getAllContacts(): Resource<ContactResponseItem> {
    return try {
        val response = api.getAllContacts()
        val result = response.body()
        if (response.isSuccessful && result != null) {
            Resource.Success(result)
        } else {
            // 提取服务器返回的错误信息
            val errorMsg = response.errorBody()?.string() ?: "请求失败"
            Resource.Error(errorMsg)
        }
    } catch (e: Exception) {
        Resource.Error(e.message ?: "网络请求异常")
    }
}

额外建议

  • 确认AndroidManifest.xml中添加了网络权限:<uses-permission android:name="android.permission.INTERNET" />
  • 给OkHttp添加日志拦截器,查看请求/响应的详细内容,快速定位问题
  • 检查服务器CORS配置,确保允许应用域名访问接口

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:40:53