如何等待异步方法

时间:2018-07-18 12:57:10

标签: java android retrofit2

我需要返回值uId。我在onResponse()函数内的第一个log语句中获得了正确的值。但是,对于return语句,它返回 null

我认为onResponse()正在另一个线程上运行。如果是这样,我该如何让 getNumber()函数等到 onResponse()函数完成执行。(就像thread.join())

还是有其他解决方案?

代码:

String uId;
public String getNumber() {

    ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
    Call<TopLead> call = apiInterface.getTopLead();
    call.enqueue(new Callback<TopLead>() {
        @Override
        public void onResponse(Call<TopLead> call, Response<TopLead> response) {
            String phoneNumber;
            TopLead topLead = response.body();
            if (topLead != null) {
                phoneNumber = topLead.getPhoneNumber().toString();
                uId = topLead.getUId().toString();
                //dispaly the correct value of uId
                Log.i("PHONE NUMBER, UID", phoneNumber +", " + uId);
                onCallCallback.showToast("Calling " + phoneNumber);
            } else {
                onCallCallback.showToast("Could not load phone number");
            }
        }

        @Override
        public void onFailure(Call<TopLead> call, Throwable t) {
            t.printStackTrace();
        }
    });
    //output: Return uid null
    Log.i("Return"," uid" + uId);
    return uId; 

4 个答案:

答案 0 :(得分:3)

您的方法执行异步请求。因此,“ return uId;”操作不会等到您的请求完成,因为它们位于不同的线程上。

我可以建议几种解决方案

  1. 使用接口回调

     public void getNumber(MyCallback callback) {
       ...
        phoneNumber = topLead.getPhoneNumber().toString();
        callback.onDataGot(phoneNumber);
     }
    

您的回调界面

     public interface MyCallback {

        void onDataGot(String number);
     }

最后,调用方法

getNumber(new MyCallback() {
    @Override
    public void onDataGot(String number) {
    // response
    }
});
  1. 使用 Kotlin 时(我认为是时候使用Kotlin代替Java了:))

    fun getNumber(onSuccess: (phone: String) -> Unit) {
      phoneNumber = topLead.getPhoneNumber().toString()
      onSuccess(phoneNumber)
    }
    

调用方法

    getNumber {
      println("telephone $it")
    }

答案 1 :(得分:0)

不返回值。因为AsyncTask是单独运行的,所以不在正常过程中运行。

因此,请使用参数创建一个方法,并将您的值传递给该方法。

答案 2 :(得分:0)

问题似乎是您想要uId而没有得到它。您的函数getNumber()执行TopDown,但您发出的请求是异步的,在另一个线程上运行。因此,在您返回uId时,uId中没有任何值。在call.enqueue所具有的回调中,我的意思是onResponse()onFailure(),您无法在uId中获得onFailure,这很明显,但并不是很明显,您会在onResponse()中得到uId。 从Javadoc进行改造:

  

onResponse       void onResponse(Call<T> call, Response<T> response)

     

为收到的HTTP响应调用。       注意:HTTP响应仍可能指示应用程序级失败,例如404或500。请调用Response.isSuccessful()以确定响应是否指示成功。

因此,在onResponse中,您仍然需要放置一些代码以确保获得uId,然后仅将其返回。并且不要直接返回uId,而是将其设置为某个字符串(全局)并在确保其可用后访问它。

因此,请更改您的代码,例如::

public void getNumber() {

ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<TopLead> call = apiInterface.getTopLead();
call.enqueue(new Callback<TopLead>() {
    @Override
    public void onResponse(Call<TopLead> call, Response<TopLead> response) {
        if(response.isSuccesful(){
            String phoneNumber;
        TopLead topLead = response.body();
        if (topLead != null) {
            phoneNumber = topLead.getPhoneNumber().toString();
            uId = topLead.getUId().toString();
            //dispaly the correct value of uId
            Log.i("PHONE NUMBER, UID", phoneNumber +", " + uId);
            onCallCallback.showToast("Calling " + phoneNumber);
            //output: Return uid 
           Log.i("Return"," uid" + uId); 

        } else {
            onCallCallback.showToast("Could not load phone number");
        }
        } else{
            Log.e("in ", " response is not successful" )
        }
    }

    @Override
    public void onFailure(Call<TopLead> call, Throwable t) {
        t.printStackTrace();
    }
});

这仍然在其他线程上运行,因此将在一段时间后设置uId。设置后即可使用该值。如果要在主线程上运行并使用Synchronous获取uId(返回call.execute().body();对象,然后可以获取{{1}),则也可以使用TopLead请求},然后使用uId

我希望它能对您有所帮助,请在注释中提出疑问。

答案 3 :(得分:0)

由于我无法理解@David 的回答,我不得不自己想出一个解决方案。我必须使用库 OkHttp3 从网络接收数据。为了解决这个问题,我使用了 LiveData

fun getText(): LiveData<String> {
    val liveData = MutableLiveData<String>()
    var result = ""
    val client = OkHttpClient()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            e.printStackTrace()
            result = e.toString()
            liveData.postValue(result)
        }

        override fun onResponse(call: Call, response: Response) {
            result = response.body.toString()
            liveData.postValue(result)
        }
    })
    return liveData
}

一旦你有了 LiveData 对象,我们就可以观察它了:

getText().observe(viewLifecycleOwner) {
    Toast.makeText(requireContext(), "Received $it", Toast.LENGTH_SHORT).show()
}