我必须通过API调用来调用服务器。我的API调用是AsyncTask,doInBackground()
包含服务器GET。onPostExecute()
将从服务器获得结果,并将JSON返回给我的活动。
问题是,我在带有return参数的方法中使用了这个api调用。
这里有一些伪代码:
private fun getDataFromServer(apiParam: Int): ArrayList<Objects> {
var extractedObjects: ArrayList<Objects> = ArrayList()
api.getDataByParameter(apiParam, object: APICallback{
override fun onError(errorJSON: JSONObject) {
errorLog: errorJSON
}
override fun onSuccess(resultJSON: JSONObject) {
extractedObjects = getObjectsFromJSON(resultJSON)
}
})
return extractedObjects
}
从API类(自定义类(添加我的API调用:
fun getDataByParameter(apiParam: Int, callback: APICallback){
class GetDataAsync(private val dataCallback: APICallback): AsyncTask<Void, Void, JSONObject>() {
override fun doInBackground(vararg p0: Void?): JSONObject {
val server = Server.getInstance(context!!)
return server.doGet(apiURL + apiParam.toString() + "/")
}
override fun onPostExecute(result: JSONObject) {
super.onPostExecute(result)
if (result!!.has("data_objects")){
dataCallback.onSuccess(result)
} else {
dataCallback.onError(result)
}
}
}
GetDataAsync(callback).execute()
}
interface APICallback{
fun onError(errorJSON:JSONObject)
fun onSuccess(resultJSON:JSONObject)
}
正如您所看到的,我必须从JSONObject
中提取对象,并将其转换为ArrayList<Objects>
(有时还需要做其他事情,如过滤(。那么我的项目会发生什么呢。当我调用getDataFromServer
时,它将向我的服务器调用AsyncTask,之后它将返回空的ArrayList。在onSuccess
中得到结果之前,方法已经结束。
所以我需要等待onSuccess
,也必须等待getObjectsFromJSON()
完成。之后,我可以返回完整的对象列表。
有什么办法可以做到这一点吗?我无法执行同步任务,因为它将触发NetworkOnMainThreadException。我必须在第二个线程中完成,但我的主线程也必须等待结果。
我必须在第二个线程中完成,但我的主线程也必须等待结果。
显然,这是两个相互矛盾的要求。NetworkOnMainThreadException
的重点不是"网络"部分,而是它是一个阻塞网络调用的事实。您不允许在UI线程上执行任何类型的阻塞调用,无论是网络调用还是其他调用。
你必须做的是安排在onPostExecute
调用中删除你的启动屏幕,而不是你显示它的UI回调方法
我强烈建议您将项目升级到Kotlin Coroutines,因为有了它们,您可以避免所有混乱的回调,并编写符合UI线程规则的顺序代码。作为一个大纲,这就是您的代码的外观:
class StartActivity : AppCompatActivity, CoroutineContext {
lateinit var masterJob: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + masterJob
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
masterJob = Job()
this.launch {
showSplash()
val result = makeNetworkCall()
updateState(result)
hideSplash()
}
}
suspend fun StartActivity.makeNetworkCall() = withContext(Dispatchers.IO) {
Server.getInstance(this).doGet(apiURL + apiParam.toString() + "/")
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // Automatically cancels all child jobs
}
}
在doInBackground((中执行网络调用。从异步任务中的onPostExecute((获取结果。