在AsyncTask

时间:2015-08-15 10:55:41

标签: java android azure asynchronous

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

这样就好了,除了我想在一个helper类中使用这些方法,这个类也可以执行其他应该是异步的东西(因此它扩展了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) {

        }
    });
}

2 个答案:

答案 0 :(得分:2)

我将在前面加上警告,我对Android也不是很熟悉。但是根据我在其他平台上的经验以及对API的快速搜索,这是我认为你应该采取的方法。我也不承诺代码片段会编译,因为我没有检查过,但他们应该接近这样做。

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

如果您希望其他内容能够等待doInBackground任务完成,那么还应返回ListenableFuture<T>,这可以通过使用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);
}

我希望指出你正确的方向。

答案 1 :(得分:0)

嗯,我用一面旗帜做了 - 但它并不漂亮。我仍然对任何更优雅或更正确的方法感兴趣。或者这实际上是正确的方法吗?

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