Java 在异步任务内使用ListenableFuture Azure调用

Java 在异步任务内使用ListenableFuture Azure调用,java,android,azure,asynchronous,Java,Android,Azure,Asynchronous,我对Android、Java和Azure有点陌生,我正在使用Azure MobileServiceClient类尝试在我的后端调用各种API。我遇到的问题是MobileServiceClient的方法似乎都是异步的,使用ListenableFutures 这很好,只是我想在助手类中使用这些方法,该类还可以做其他应该是异步的事情(因此它扩展了AsyncTask)。但是,由于MobileServiceClient调用是异步的,因此会导致AsyncTask过早返回。我希望AsyncTask在Mobil

我对Android、Java和Azure有点陌生,我正在使用Azure MobileServiceClient类尝试在我的后端调用各种API。我遇到的问题是MobileServiceClient的方法似乎都是异步的,使用ListenableFutures

这很好,只是我想在助手类中使用这些方法,该类还可以做其他应该是异步的事情(因此它扩展了AsyncTask)。但是,由于MobileServiceClient调用是异步的,因此会导致AsyncTask过早返回。我希望AsyncTask在MobileServiceClient方法返回之前不要调用其onPostExecute方法

我如何避免这个问题?我需要改变我的架构吗?是否可以将MobileServiceClient调用放在另一个异步任务中并让它阻止它

@Override
protected Boolean doInBackground(Void... params) {
    Log.i(TAG, "Doing background task");
    if(mTaskType==tTaskType.LOGIN_TASK){
        login();
        //do other stuff here that should be async
    }
    return true;
} 

private void login(){
    Log.i(TAG, "Doing login task...");
    ListenableFuture<JsonElement> result = mClient.invokeApi("login",    mJSONHelper.makeLoginObject(thisUser));
    Futures.addCallback(result, new FutureCallback<JsonElement>() {
        @Override
        public void onFailure(Throwable exc) {
            error.setError(ErrorHelper.Error.NETWORK_ERROR);
        }

        @Override
        public void onSuccess(JsonElement result) {

        }
    });
}
@覆盖
受保护的布尔doInBackground(Void…params){
Log.i(标记“执行后台任务”);
如果(mTaskType==tTaskType.LOGIN\u任务){
登录();
//在这里做其他应该是异步的事情
}
返回true;
} 
私有void登录(){
i(标记“正在执行登录任务…”);
ListenableFuture result=mClient.invokeApi(“login”,mJSONHelper.makeLoginObject(thisUser));
Futures.addCallback(结果,newfuturecallback(){
@凌驾
公共失效失效失效(可丢弃的exc){
error.setError(ErrorHelper.error.NETWORK_error);
}
@凌驾
成功时公共无效(JsonElement结果){
}
});
}

好吧,我是用一面旗子做的——虽然不好看。我仍然对任何更优雅或正确的方法感兴趣。或者这真的是正确的方法吗

 private void login(){
    Log.i(TAG, "Doing login task...");
    isLoginFinished= false;
    ListenableFuture<JsonElement> result = mClient.invokeApi("login", mJSONHelper.makeLoginObject(thisUser));
    Futures.addCallback(result, new FutureCallback<JsonElement>() {
        @Override
        public void onFailure(Throwable exc) {
            error.setError(ErrorHelper.Error.NETWORK_ERROR);
            isLoginFinished= true;
        }

        @Override
        public void onSuccess(JsonElement result) {
            Log.i(TAG, "Login call was successful, parsing result:" + result.toString());
            isLoginFinished= true;
        }
    });
    while(!isLoginFinished); 
}
private void login(){
i(标记“正在执行登录任务…”);
isLoginFinished=false;
ListenableFuture result=mClient.invokeApi(“login”,mJSONHelper.makeLoginObject(thisUser));
Futures.addCallback(结果,newfuturecallback(){
@凌驾
公共失效失效失效(可丢弃的exc){
error.setError(ErrorHelper.error.NETWORK_error);
isLoginFinished=true;
}
@凌驾
成功时公共无效(JsonElement结果){
i(标记“登录调用成功,解析结果:”+result.toString());
isLoginFinished=true;
}
});
而(!isLoginFinished);
}

我将在序言中提出警告,我对Android也不是很熟悉。然而,根据我在其他平台上的经验和对API的快速搜索,我认为您应该采用这种方法。我也不保证代码片段会编译,因为我还没有检查过,但它们应该已经接近编译了

您的
login
方法应该返回一个
ListenableFuture
,然后
doInBackground
方法可以添加自己的回调,该回调在登录完成时执行

如果您希望其他内容能够等待
doInBackground
任务完成,那么还应该返回一个
ListenableFuture
,可以使用
Futures.transform
方法将一系列异步调用链接在一起

我认为它应该是这样的:

protected void doInBackground(Void... params) {
    Log.i(TAG, "Doing background task");
    if(mTaskType==tTaskType.LOGIN_TASK){
        var loginFuture = ListenableFuture<UserDetail> login();

        Futures.addCallback(loginFuture, new FutureCallback<UserDetail>() {
            @Override
            public void onSuccess(UserDetail userDetail)
            {
                // do other stuff here that should be async
                // also optionally you could implement this as a transform
                // style thing to and return another future from this `doInBackground`
                // method so other parts of your code could know when it is completed.
            }

            @Override
            public void onFailure(Throwable exc) { 
                // I'd quite likely move the error handling from the login method here
                // as that way it can also handle any exceptions caused by the transform
                // from json to user detail as well. 
            }
        })
    }
} 

private ListenableFuture<UserDetail> login(){
    Log.i(TAG, "Doing login task...");
    ListenableFuture<JsonElement> loginFutureResult = mClient.invokeApi("login",    mJSONHelper.makeLoginObject(thisUser));
    Futures.addCallback(loginFutureResult, new FutureCallback<JsonElement>() {
        @Override
        public void onFailure(Throwable exc) {
            // This is just to keep with what your style is, for recording the error
            // I think you might be better off handling it at a higher level and
            // also you might want to check `exc` to see if it was an actual network
            // error and not for example just failed credentials or something.
            error.setError(ErrorHelper.Error.NETWORK_ERROR);
        }

        @Override
        public void onSuccess(JsonElement result) {
            Log.i(TAG, "The login was successful");
        }
    });

    // lets pretend that instead of returning the JSON response 
    // you wanted to map it to a user detail before returning, just to show how to do that.

    AsyncFunction<JsonElement, UserDetail> transformUserJsonFunction =
        new AsyncFunction<JsonElement, UserDetail>() {
            public ListenableFuture<UserDetail> apply(JsonElement userJson) {
                // some code to map the json element to user detail
                UserDetail userDetail = new UserDetail(userJson);
                return Futures.immediateFuture(userDetail);
            }
        };


    return Futures.transform(loginFutureResult, transformUserJsonFunction);
}
受保护的void doInBackground(void…params){
Log.i(标记“执行后台任务”);
如果(mTaskType==tTaskType.LOGIN\u任务){
var loginFuture=ListenableFuture login();
Futures.addCallback(loginFuture,newfuturecallback(){
@凌驾
成功时的公共void(UserDetail UserDetail)
{
//在这里做其他应该是异步的事情
//还可以选择将其实现为转换
//从这个“做的事”的背景中创造出另一个未来`
//方法,以便代码的其他部分可以知道它何时完成。
}
@凌驾
失效时的公共无效(可丢弃的exc){
//我很可能会将错误处理从登录方法移到这里
//这样,它还可以处理由转换引起的任何异常
//从json到用户详细信息。
}
})
}
} 
私有ListenableFuture登录(){
i(标记“正在执行登录任务…”);
ListenableFuture loginFutureResult=mClient.invokeApi(“login”,mJSONHelper.makeLoginObject(thisUser));
Futures.addCallback(loginFutureResult,newfuturecallback(){
@凌驾
公共失效失效失效(可丢弃的exc){
//这只是为了保持你的风格,记录错误
//我认为你最好从更高的层次和更高的层次来处理它
//另外,您可能需要检查'exc',看看它是否是一个实际的网络
//错误,而不仅仅是失败的凭证或其他东西。
error.setError(ErrorHelper.error.NETWORK_error);
}
@凌驾
成功时公共无效(JsonElement结果){
Log.i(标记“登录成功”);
}
});
//让我们假设它不是返回JSON响应
//您希望在返回之前将其映射到用户详细信息,只是为了演示如何执行此操作。
AsyncFunction transformUserJsonFunction=
新的异步函数(){
public ListenableFuture应用(JsonElement userJson){
//一些将json元素映射到用户详细信息的代码
UserDetail UserDetail=新的UserDetail(userJson);
返回期货。即时期货(用户详细信息);
}
};
return Futures.transform(loginFutureResult,transformUserJsonFunction);
}

我希望这为您指明了正确的方向。

这将使您的一个处理器内核保持100%的性能,直到网络呼叫完成,因为它处于一个紧密的循环中。谢谢Caleb,这无疑为我指明了正确的方向。它看起来像是一个小男孩