【问题标题】:Return a value from callback which is situated in an async task doInBackGround从回调中返回一个值,该值位于异步任务 doInBackGround
【发布时间】:2014-03-07 09:10:21
【问题描述】:

我有以下代码:

这里是 asyncHttp 文档的链接: Link

这就是所谓的登录任务:

mAuthTask = new UserLoginTask();
mAuthTask.execute((Void) null);

这是android模板活动提供的异步任务:

    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        // TODO: attempt authentication against a network service.

        Network.login(mEmail, mPassword, new AsyncHttpResponseHandler() {

            @Override
            public void onSuccess(int statusCode, Header[] headers,
                    byte[] responseBody) {

                if (statusCode == 200) {
                    // Successfully got a response
                    for (int i = 0; i < headers.length; i++) {
                        if (headers[i].getName().equalsIgnoreCase("token")) {
                            // Set the token to the received value
                            Network.SetToken(headers[i].getValue());
                    // >>>>>>>      return true;   <<<<<<<<<
                        }
                    }
                }
                // >>>>> return false  <<<<<<<<<<<<

            }

            @Override
            public void onFailure(int statusCode, Header[] headers,
                    byte[] responseBody, Throwable error) {
                // Response failed :(
                  //     >>>>>>>>>>>>>>>>>> return false <<<<<<<<<<<<<
            }           
        });

        // TODO: register the new account here.
        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
        } else {
            mPasswordView
                    .setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();
        }
    }

如何从我的 AsyncHttpResponseHandler 中返回 true 或 false,然后将该值返回给异步任务?这样它就可以成功执行其 on post 方法。

我只能想到设置变量然后阻止它。但是那失败主义者认为它是异步的,我宁愿远离它。

【问题讨论】:

  • 问题出在哪里?
  • Network.login 不是已经与 AsyncHttpResponseHandler 异步了吗?
  • @super-qua 是的。但我不认为它的成功方法会在用户线程上运行吗?因为我必须在我的回调中更新 UI,并且不允许你从工作线程更新 ui。
  • activity.runOnUiThread(new Runnable() { @Override public void run() { 改变你的 UI } } );
  • 你可以按照@anthone 提到的方式解决它

标签: java android android-asynctask callback


【解决方案1】:

来自开发者文档

AsyncTask 允许正确且轻松地使用 UI 线程。此类允许在 UI 线程上执行后台操作并发布结果,而无需操作线程和/或处理程序。AsyncTask 旨在成为围绕 Thread 和 Handler 的帮助类,不构成通用线程框架。理想情况下,AsyncTasks 应该用于短操作(最多几秒钟。)

现在说如果你真的想在onPostExecute 结束,你可以这样做

public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
    @Override
    protected Boolean doInBackground(Void... params) {
        // TODO: attempt authentication against a network service.

        final ResponseContainer responseContainer = new ResponseContainer();
        Network.login(mEmail, mPassword, new AsyncHttpResponseHandler() {

            @Override
            public void onSuccess(int statusCode, Header[] headers,
                    byte[] responseBody) {

                if (statusCode == 200) {
                    // Successfully got a response
                    for (int i = 0; i < headers.length; i++) {
                        if (headers[i].getName().equalsIgnoreCase("token")) {
                            // Set the token to the received value
                            Network.SetToken(headers[i].getValue());
                    // >>>>>>>      return true;   <<<<<<<<<
                            responseContainer.result = true;
                        }
                    }
                }
                // >>>>> return false  <<<<<<<<<<<<
                responseContainer.result = false;
            }

            @Override
            public void onFailure(int statusCode, Header[] headers,
                    byte[] responseBody, Throwable error) {
                // Response failed :(
                  //     >>>>>>>>>>>>>>>>>> return false <<<<<<<<<<<<<
                responseContainer.result = false;
            }           
        });

        // TODO: register the new account here.
        return responseContainer.result;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
        } else {
            mPasswordView
                    .setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();
        }
    }

    private class ResponseContainer {
        public boolean result;
    }
}

【讨论】:

  • 我和作者有同样的问题,我对@Neil 的回答有点怀疑。使用AsyncHttpResponseHandler(一般是接口)会异步执行,所以会在onSuccess或onFailure之前执行return responseContainer.result。对 ?或者也许确实如此,但这将是出乎意料的!感谢澄清;-)
【解决方案2】:

当且仅当网络调用在其自己的线程上运行时,您可以尝试通过阻止 doInBackground 来执行此操作,方法是确定网络调用使用哪个线程并使用 Thread.join

但是,我认为您不能保证它会,因为您没有指定执行程序,并且可以在您提供的代码之外更改。因此,如果我遇到这个问题,我会转过代码并使用AsyncHandler 来响应网络调用的响应,从而完全避免嵌套异步操作。像这样的:

public void loginUser() {
    Network.login(mEmail, mPassword, new AsyncHttpResponseHandler() {

        @Override
        public void onSuccess(int statusCode, Header[] headers,
                byte[] responseBody) {

            if (statusCode == 200) {
                // Successfully got a response
                for (int i = 0; i < headers.length; i++) {
                    if (headers[i].getName().equalsIgnoreCase("token")) {
                        // Set the token to the received value
                        Network.SetToken(headers[i].getValue());
                        new RegisterUserTask(statusCode, responseBody).execute();
                    }
                }
            }
            // respond to a failed authentication.
            mPasswordView
                .setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();

        }

        @Override
        public void onFailure(int statusCode, Header[] headers,
                byte[] responseBody, Throwable error) {
            // Response failed :(
              // Show some sort of error.
        }           
    });
}

public class RegisterUserTask extends AsyncTask<Void, Void, Boolean> {
    private int statusCode;
    private byte[] body;

    public RegisterUserTask(int statusCode, byte[] body) {
        this.statusCode = statusCode;
        this.body = body;
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        // TODO: register the new account here.

        return true;
    }

    @Override
    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;
        showProgress(false);

        if (success) {
            finish();
        }
    }
}

【讨论】:

  • BUt `public void onSuccess(` 会在用户线程上运行吗?
  • 如果我们谈论的是android-async-http 库,那么是的。 From the docs (on the top of the page):“所有请求都是在你应用的主 UI 线程之外发出的,但是任何回调逻辑都将在创建回调的同一线程上执行……”
  • 好吧,在这种情况下,这很容易。感谢您确认
【解决方案3】:

Network.login 不是已经异步了吗?

你可以使用Handler系统:

private static final int SUCCESS= 0;
private static final int FAIL= 1;
//In your class
    private final Handler handler = new Handler() {

        @Override
        public void handleMessage(final Message msg) {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    switch (msg.what) {
                        case SUCCESS:
                            finish();
                            break;
                        case FAIL:
                            mPasswordView.setError(getString(R.string.error_incorrect_password));
                            mPasswordView.requestFocus();
                            break;
                        default:
                            break;
                    }
                }
            });
        }
    };

    public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
        @Override
        protected Boolean doInBackground(Void... params) {
            // TODO: attempt authentication against a network service.

            Network.login(mEmail, mPassword, new AsyncHttpResponseHandler() {

                @Override
                public void onSuccess(int statusCode, Header[] headers,
                        byte[] responseBody) {

                    if (statusCode == 200) {
                        // Successfully got a response
                        for (int i = 0; i < headers.length; i++) {
                            if (headers[i].getName().equalsIgnoreCase("token")) {
                                // Set the token to the received value
                                Network.SetToken(headers[i].getValue());
                                handler.sendEmptyMessage(SUCCESS);
                            }
                        }
                    }
                    // >>>>> return false  <<<<<<<<<<<<
                    handler.sendEmptyMessage(FAIL);
                }

                @Override
                public void onFailure(int statusCode, Header[] headers,
                        byte[] responseBody, Throwable error) {
                    // Response failed :(
                    handler.sendEmptyMessage(FAIL);
                      //     >>>>>>>>>>>>>>>>>> return false <<<<<<<<<<<<<
                }           
            });

            // TODO: register the new account here.
            return true;
        }

        @Override
        protected void onPostExecute(final Boolean success) {

        }
    }

但我认为您不必将 asyncTask 与 Network.login 一起使用。 如果它是同步的,可能只是一个新线程?

new Thread() {
                @Override
                public void run() {
                    Network.login(...) {
                       ...
                    }
                };
 }.start();

【讨论】:

    【解决方案4】:

    如果我明白你的意思,你的意思是找到一种方法来处理像 AsyncTaskCompleted 这样的事件并在那里做你的员工。解决方案是定义一个类似 WebServiceCallbackProxy 的接口:

    public interface WebServiceCallbackProxy {
    
        void CallBack(char[] jsonData, String serviceName, boolean isCommunicationSucceed, HttpRequestType reguestType, String serviceTicket);
    }
    

    然后在你的 AsyncTask 中定义一个实例:

    public class AsynServiceCall extends AsyncTask<String, Integer, char[]> {
    
    WebServiceCallbackProxy proxy;
    .... 
    public AsynServiceCall(WebServiceCallbackProxy webServiceProxy, ProgressDialog progressDialog) {
        this.proxy = webServiceProxy;
    
    }
    

    然后在 PostExecute 上调用您的 CallBackMethod:

    protected void onPostExecute(char[] response) {
            if (this.progressDialog != null) {
                progressDialog.dismiss();
            }
            if(proxy != null)
                proxy.CallBack(response, this.serviceName, this.isCommunicationSucced, this.requestType, this.serivceTicket);
        }
    

    这样做,您就有了一个具有 OnCompleted 回调方法的 AsyncTask。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-22
      • 2021-04-06
      • 2017-12-16
      • 2017-07-19
      • 1970-01-01
      • 2021-04-04
      相关资源
      最近更新 更多