如何等待AsyncTask完成?

时间:2018-08-02 11:18:43

标签: android android-asynctask kotlin

我必须通过API调用来调用服务器。我的API调用是AsyncTask,其中doInBackground()包含服务器GET。 onPostExecute()将从服务器获取结果,并将JSON返回我的活动。

问题是,我正在带有返回参数的方法中使用此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 。我必须在第二个线程中执行此操作,但是我的主线程也必须等待结果。

2 个答案:

答案 0 :(得分:1)

在doInBackground()中进行网络调用。 从异步任务中的onPostExecute()获取结果。

答案 1 :(得分:1)

  

我必须在第二个线程中执行此操作,但我的主线程也必须等待结果。

显然,这是两个矛盾的要求。 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
    }
}