简体   繁体   English

如何等待AsyncTask完成?

[英]How to wait for AsyncTask to finish?

I have to call server through the API call. 我必须通过API调用来调用服务器。 My API call is AsyncTask with doInBackground() containing server GET. 我的API调用是AsyncTask,其中doInBackground()包含服务器GET。 onPostExecute() will get result from server and it will return JSON back to my activity. onPostExecute()将从服务器获取结果,并将JSON返回我的活动。

Problem is, that I'm using this api call inside the method with return parameter. 问题是,我在带有return参数的方法中使用此api调用。

Some pseudocode here: 一些伪代码在这里:

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
}

Adding my API Call from API class (custom class): 从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)
}

As you can see, I have to extract objects from JSONObject and convert it to ArrayList<Objects> (sometimes do other stuff like filtering). 如您所见,我必须从JSONObject提取对象并将其转换为ArrayList<Objects> (有时还会执行其他操作,例如过滤)。 So what will happen in my program. 所以我的程序会发生什么。 As I call getDataFromServer it will call AsyncTask to my server and after that it will return empty ArrayList. 当我调用getDataFromServer ,它将调用AsyncTask到我的服务器,此后它将返回空的ArrayList。 Until result is available in onSuccess , method is already over. 直到onSuccess结果可用为止,方法已经结束。

So I need to wait for onSuccess and also I have to wait for getObjectsFromJSON() to be finished. 因此,我需要等待onSuccess ,也必须等待getObjectsFromJSON()完成。 After that I can return my full list of objects. 之后,我可以返回对象的完整列表。

Is there any way how to achieve this? 有什么办法可以做到这一点? I cant do synchronous task, because it will fire NetworkOnMainThreadException . 我无法执行同步任务,因为它将触发NetworkOnMainThreadException I have to do it in second thread, but also my main thread has to wait for results. 我必须在第二个线程中执行此操作,但是我的主线程也必须等待结果。

Do the network call inside doInBackground(). 在doInBackground()内部进行网络调用。 get the result from onPostExecute() in the Async task. 从Async任务中的onPostExecute()获取结果。

I have to do it in second thread, but also my main thread has to wait for results. 我必须在第二个线程中执行此操作,但是我的主线程也必须等待结果。

Clearly, these are two contradictory requirements. 显然,这是两个矛盾的要求。 The point of the NetworkOnMainThreadException isn't the "network" part, but the fact that it's a blocking network call. NetworkOnMainThreadException的重点不是“网络”部分,而是事实,它是阻塞的网络调用。 You aren't allowed to perform any kind of blocking calls on the UI thread, be it network or anything else. 不允许在UI线程上执行任何类型的阻止调用,无论是网络调用还是其他操作。

What you must do is arrange for your splash screen to be removed within the onPostExecute call instead of the UI callback method where you show it. 您必须要做的是安排在onPostExecute调用中删除初始屏幕,而不是在显示它的UI回调方法中移除。

I would highly recommend upgrading your project to Kotlin Coroutines because with them you can avoid all the messy callbacks and write sequential-looking code which nevertheless satisfies the rules of the UI thread. 我强烈建议您将项目升级到Kotlin Coroutines,因为有了它们,您可以避免所有混乱的回调,并编写顺序可见的代码,这些代码仍然可以满足UI线程的规则。 As an outline, this is how your code would look: 概括来说,这就是您的代码的外观:

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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM