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

如何通过Android WebView实现Android向HTML传递响应JSON?

解决Android异步调用导致返回值为null的问题

嗨,这个异步调用的坑我之前也踩过!别着急,咱们先把核心问题捋清楚:你的getData()是异步操作(比如读取Asset、网络请求这类耗时操作,通常会放到后台线程执行),而load()是同步执行的——主线程不会等getData()跑完就直接返回了,这时候自然拿不到数据。断点调试时你手动暂停了主线程,等异步操作完成了才继续,所以能拿到预期结果。

下面给你几种常用的解决方案,你可以根据项目架构选合适的:

方案1:使用回调接口(Java/Kotlin通用)

这是最基础的异步处理方式,通过回调通知数据加载完成:

步骤1:定义回调接口

// Java项目改成interface DataCallback { ... }即可
interface DataCallback {
    fun onDataLoaded(jsonObject: JSONObject)
    fun onError(error: Exception)
}

步骤2:修改getData()方法,接收回调

把原来的返回值改成通过回调传递:

fun getData(callback: DataCallback) {
    // 把耗时操作放到后台线程(这里用AsyncTask举例,也可以用ThreadPoolExecutor等)
    AsyncTask.execute {
        try {
            // 你的实际异步逻辑:比如读取Asset中的JSON文件
            val inputStream = assets.open("your_data.json")
            val jsonString = inputStream.bufferedReader().use { it.readText() }
            val jsonObject = JSONObject(jsonString)
            
            // 数据加载完成,回调主线程处理
            callback.onDataLoaded(jsonObject)
        } catch (e: Exception) {
            // 处理异常
            callback.onError(e)
        }
    }
}

步骤3:修改load()方法,在回调中处理结果

现在load()不再直接返回值,而是等待回调触发后执行后续逻辑:

fun load() {
    getData(object : DataCallback {
        override fun onDataLoaded(jsonObject: JSONObject) {
            // 这里拿到了非null的JSON数据!
            // 注意:异步操作在后台线程,更新UI/启动Activity要切回主线程
            runOnUiThread {
                // 唤起目标Activity并传递数据
                val intent = Intent(this@YourActivity, TargetActivity::class.java)
                intent.putExtra("JSON_DATA", jsonObject.toString())
                startActivity(intent)
                
                // 或者更新WebView展示JSON
                webView.loadData(jsonObject.toString(), "application/json", "utf-8")
            }
        }

        override fun onError(error: Exception) {
            // 错误处理,比如提示用户
            runOnUiThread {
                Toast.makeText(this@YourActivity, "数据加载失败:${error.message}", Toast.LENGTH_SHORT).show()
            }
        }
    })
}

方案2:使用Kotlin协程(推荐Kotlin项目使用)

协程可以让异步代码写起来像同步一样,更简洁:

步骤1:把getData()改成挂起函数

// 用withContext切换到IO线程执行耗时操作
suspend fun getData(): JSONObject = withContext(Dispatchers.IO) {
    val inputStream = assets.open("your_data.json")
    val jsonString = inputStream.bufferedReader().use { it.readText() }
    JSONObject(jsonString)
}

步骤2:在load()中启动协程

借助lifecycleScope(AndroidX提供,自动和生命周期绑定):

fun load() {
    lifecycleScope.launch {
        try {
            // 这里会等待getData()执行完成,再继续往下走
            val jsonObject = getData()
            
            // 拿到数据后执行后续逻辑
            val intent = Intent(this@YourActivity, TargetActivity::class.java)
            intent.putExtra("JSON_DATA", jsonObject.toString())
            startActivity(intent)
        } catch (e: Exception) {
            Toast.makeText(this@YourActivity, "数据加载失败:${e.message}", Toast.LENGTH_SHORT).show()
        }
    }
}

方案3:使用LiveData(适合MVVM架构)

如果你的项目用了MVVM,可以把数据放到LiveData中,在UI层观察数据变化:

步骤1:在ViewModel中定义LiveData

class YourViewModel : ViewModel() {
    private val _dataLiveData = MutableLiveData<JSONObject>()
    val dataLiveData: LiveData<JSONObject> = _dataLiveData

    fun getData(context: Context) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                // 读取Asset数据
                val inputStream = context.assets.open("your_data.json")
                val jsonString = inputStream.bufferedReader().use { it.readText() }
                val jsonObject = JSONObject(jsonString)
                
                // 把数据post到LiveData
                _dataLiveData.postValue(jsonObject)
            } catch (e: Exception) {
                // 处理异常
            }
        }
    }
}

步骤2:在Activity/Fragment中观察LiveData

class YourActivity : AppCompatActivity() {
    private lateinit var viewModel: YourViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProvider(this)[YourViewModel::class.java]
        
        // 观察数据变化
        viewModel.dataLiveData.observe(this) { jsonObject ->
            // 拿到数据后执行逻辑
            val intent = Intent(this, TargetActivity::class.java)
            intent.putExtra("JSON_DATA", jsonObject.toString())
            startActivity(intent)
        }
    }

    fun load() {
        // 触发数据加载
        viewModel.getData(this)
    }
}

总结一下:核心就是不要让同步代码等待异步操作,而是通过回调、协程、LiveData等方式,让异步操作完成后再通知主线程处理结果。这样就不会出现返回值为null的问题啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:18:01