【问题标题】:Problem with Toast in AsyncTask method callAsyncTask 方法调用中的 Toast 问题
【发布时间】:2011-04-21 17:29:05
【问题描述】:

大家好,
我有一个将一些数据发布到服务器的 AsyncTask。它通过调用我从 doInBackground 编写的静态方法来实现这一点。当我运行 AsyncTask 时,我发送调用 execute() 的活动的上下文,我将其发送到我的静态方法,因为如果在与服务器通信时出现问题,它需要它来制作 Toast。但是,当在静态方法中创建 Toast 时出现此错误:

04-21 12:49:16.689: ERROR/AndroidRuntime(2123): FATAL EXCEPTION: AsyncTask #1
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): java.lang.RuntimeException: An error occured   while executing doInBackground()
04-21 12:49:16.689: ERROR/AndroidRuntime(2123):at android.os.AsyncTask$3.done(AsyncTask.java:200)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.FutureTask.run(FutureTask.java:138)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.lang.Thread.run(Thread.java:1019)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at android.os.Handler.<init>(Handler.java:121)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at android.widget.Toast.<init>(Toast.java:68)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at android.widget.Toast.makeText(Toast.java:23
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at com.microogle.dev.util.ServerConnections.PostToLoginPage(ServerConnections.java:36)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at com.microogle.dev.Whiteboard.WhiteboardLogin$LoginTask.doInBackground(WhiteboardLogin.java:150)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at com.microogle.dev.Whiteboard.WhiteboardLogin$LoginTask.doInBackground(WhiteboardLogin.java:1)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at android.os.AsyncTask$2.call(AsyncTask.java:185)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
04-21 12:49:16.689: ERROR/AndroidRuntime(2123): ... 4 more

随后出现泄漏窗口错误。我假设这是因为在静态方法中传递给 Toast 的上下文出错。 AsyncTask 是:

private class LoginTask extends AsyncTask<Void, Void, Void> {

    private WhiteboardLogin activity;
    private Context callingContext;
    private ProgressDialog dialog;
    private String user, pass;
    private boolean sendIntent = true, loginError = false, populateError = false;

    public LoginTask(WhiteboardLogin activity, String user, String pass, Context callingContext){
        this.activity = activity;
        this.user = user.trim();
        this.pass = pass.trim();
        this.callingContext = callingContext;
    }
@Override
    protected Void doInBackground(Void... params) {
        ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair("user",user));
        nameValuePairs.add(new BasicNameValuePair("pass",pass));
        sessionUser = user;
        sessionPassword = pass;
        //Posts the username and password to the login page and toasts an error if the login doesn't work 
        if(ServerConnections.PostToLoginPage(callingContext, nameValuePairs, activity.getString(R.string.loginPageURI)) == 1){
            dialog.dismiss();
            sendIntent = false;
            loginError = true;
            publishProgress();
           return null;
        }
        else{
           userDataList = populateUserDataList(callingContext, user,pass);
           if(userDataList == null){
               dialog.dismiss();
               sendIntent = false;
               populateError = true;
               return null;
           }
       }
       return null;
    }

【问题讨论】:

    标签: android thread-safety android-asynctask toast


    【解决方案1】:

    doInBackground() 方法中的代码在其自己的线程上运行,因此您无法直接从那里访问任何 UI 元素,因为它们在 UI 线程上运行。

    所以你有两个选择。

    1. 您在 UI 线程上运行的 onPreExecute()onPostExecute() 方法中处理所有 UI 内容。

    2. 您在 onProgressUpdate() 方法中处理 UI 内容,该方法也在 UI 线程上运行。您可以通过调用publishProgress() 从doInBackground() 中触发此方法。

    【讨论】:

      【解决方案2】:

      你可以在 doInBackground 中 Toast

      使用此代码

      runOnUiThread(new Runnable() {
      public void run() {
      
          Toast.makeText(<your class name>.this, "Cool Ha?", Toast.LENGTH_SHORT).show();
          }
      });
      

      【讨论】:

        【解决方案3】:

        您正在尝试更新doInBackground() 中的 UI,该 UI 在与 UI 线程不同的另一个线程中运行。 您应该在 AsyncTask 的 onPostExecute() 方法中显示 Toast:http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)

        【讨论】:

        • 我在 onPostExecute() 中显示了其他 Toast,但导致问题的方法是在另一个类中的方法中,在 doInBackground() 中被调用,所以我无法把它放到onPostExecute()
        • 我认为您需要处理您的逻辑,该静态方法不应显示 Toast。无论如何,您可以使用处理程序而不是上下文来做您想做的事情,在您的 Activity 中创建一个处理程序,然后将其转发给静态方法。需要时,将显示 Toast 的可运行文件发布到处理程序
        • 我实际上只是使用 Toast 进行调试(可能应该使用 Log),我只是想知道是否可以做这样的事情对我来说会更好。
        • 哦,好的,是的,将日志用于调试目的更安全:)
        【解决方案4】:

        是的,使用日志进行调试是最简单的,但是如果您确实有消息需要在后台处理期间显示,无论出于何种原因,您都可以使用 onProgressUpdate() 方法,正如 Flo 上面提到的。您可以在需要编写消息时触发此方法,方法是从 DoInBackground() 中调用 publishProgress()。消息内容或处理状态可以通过 ASyncTask 中的私有变量轻松传递,Background 方法和 UI 方法都可以访问这些私有变量。

        【讨论】:

          猜你喜欢
          • 2011-09-13
          • 2019-11-08
          • 1970-01-01
          • 2014-07-19
          • 2015-09-01
          • 1970-01-01
          • 2014-05-06
          • 2015-04-23
          • 1970-01-01
          相关资源
          最近更新 更多