【问题标题】:How to display a Toast in Android AsyncTask?如何在 Android AsyncTask 中显示 Toast?
【发布时间】:2013-05-30 07:22:23
【问题描述】:

我正在尝试在使用 AsyncTask<URL, Integer, Long> 扩展的 initial_background 类中显示 Toast。我在 logcat 中收到此错误。

public class InitialBackgroundTask extends AsyncTask<URL, Integer, Long> {

    @Override
    protected Long doInBackground(URL... params) {
        // TODO Auto-generated method stub
        show a = new show();
        a.loop();
        return null;
    }

public class show {

    void loop()
    {
        for(int i=0; i<10; i++)
        {
            Toast.makeText(MainActivity.me, "test", Toast.LENGTH_LONG).show();
        }
    }
}

这是个例外:

05-30 12:08:12.641: E/AndroidRuntime(30840): FATAL EXCEPTION: AsyncTask #1
05-30 12:08:12.641: E/AndroidRuntime(30840): java.lang.RuntimeException: An error occured while executing doInBackground()
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.os.AsyncTask$3.done(AsyncTask.java:278)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.lang.Thread.run(Thread.java:856)
05-30 12:08:12.641: E/AndroidRuntime(30840): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.os.Handler.<init>(Handler.java:121)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.widget.Toast$TN.<init>(Toast.java:317)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.widget.Toast.<init>(Toast.java:91)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.widget.Toast.makeText(Toast.java:233)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at   com.example.toast.show.loop(show.java:11)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at com.example.toast.InitialBackgroundTask.doInBackground(InitialBackgroundTask.java:13)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at com.example.toast.InitialBackgroundTask.doInBackground(InitialBackgroundTask.java:1)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at android.os.AsyncTask$2.call(AsyncTask.java:264)
05-30 12:08:12.641: E/AndroidRuntime(30840):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
05-30 12:08:12.641: E/AndroidRuntime(30840):    ... 5 more

上面的代码展示了整个故事。实际上,我想在 doInBackground 方法中显示 toast

【问题讨论】:

  • 在 doinBanckground() 中你不能做任何与 UI 相关的事情,尝试在 PostExecute() 方法中显示你的 toast。
  • 实际上,我正在从 URls 下载一些数据,并且我有四个 Urls 我想显示 toast 一个一个下载一个 url 等等。因此,如果我在帖子中执行此操作,它将无法一一显示,而只会显示最终结果。

标签: android android-asynctask toast


【解决方案1】:

您无法在后台线程上更新 UI。 doInBackground() 在后台线程上调用。您应该在 UI 线程上更新 UI。

      runOnUiThread(new Runnable(){

          @Override
          public void run(){
            //update ui here
            // display toast here 
          }
       });

onPreExecute()onPostExecute(Result) 在 UI 线程上调用。所以你可以在这里显示 toast。

onProgressUpdate(Progress...),在调用 publishProgress(Progress...) 后在 UI 线程上调用,可用于动画进度条或在文本字段中显示日志。

doInBackground() 计算的结果是onPostExecute(Result) 的参数,所以在doinBackground() 中返回结果并在onPostExecute(Result) 中显示您的吐司

您还可以使用@Stine Pike 建议的处理程序

为清楚起见,请查看以下主题下的链接:4 个步骤

http://developer.android.com/reference/android/os/AsyncTask.html

【讨论】:

    【解决方案2】:

    创建一个处理程序对象并使用它执行所有 Toast 消息。

    @Override
    protected Void doInBackground(Void... params) {
        Handler handler =  new Handler(context.getMainLooper());
        handler.post( new Runnable(){
            public void run(){
                Toast.makeText(context, "Created a server socket",Toast.LENGTH_LONG).show(); 
            }
        });
      }
    

    【讨论】:

    • 上下文呢?
    • 如果您对context.getMainLooper() 感到困惑,可以使用Looper.getMainLooper() 来帮助您。
    【解决方案3】:

    这是另一种方式,这里没有提到如下:

    第 1 步:Handler 定义为全局

    Handler handler;
    

    第 2 步:doInBackground() 方法中初始化处理程序,如下所示:

    @Override
    protected Void doInBackground(Void... params) {
        Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
               //your code
            }
        }
      };
    }
    

    第 3 步: 现在您可以通过调用在代码中的任何位置调用该处理程序

    if(handler != null){
      handler.sendEmptyMessage(1);
    }
    

    您可以做的更多是您可以通过处理程序发送数据,如下所示:

    Message message = new Message();
    Bundle bundle = new Bundle();
    bundle.putInt("KEY", value);
    message.setData(bundle);
    handler.sendMessage(message);
    

    并在您的处理程序中处理数据,如下所示

    handler = new Handler(){ 
        @Override
        public void handleMessage(Message message) {
            Bundle bundle = message.getData();
            Integer value = bundle.getInt("KEY");
    
        }
    };
    

    【讨论】:

      【解决方案4】:

      在 onPostExecute 或 onPreExecute 中显示您的 Toast。 doInBackGround 在单独的线程上运行,但其他两个方法在 UI 线程上运行。

      但如果一定要在doInBackGround中显示toast,则可以使用Handler.postrunonUiThread进行toast显示。

      【讨论】:

        【解决方案5】:

        您无法在非 UI 线程中显示 Toast(即在后台执行)。您可以尝试 flag 概念。

        public class HttpRequest extends AsyncTask<String[], Void, String> {
            boolean flag=false;
        ....
        ...
        ....
         @Override
            protected String doInBackground(String[]... params) {
           //set flag as true when you need to trigger the Toast
         try{
           //Some Network Calls
             } catch (HttpHostConnectException e) {
            flag=true;   
          //Triggered Flas when i got Exceptions          
               }
        }
         @Override
            protected void onPostExecute(String result) {
                if(flag){
                    Toast.makeText(activity, "HttpHostConnectException Occured ", Toast.LENGTH_SHORT).show();
                }
        
        
        }
        

        快乐编码..!!!在此处输入代码

        【讨论】:

          【解决方案6】:

          您正试图在非 ui 线程中显示 toast,这就是出现此错误的原因。

          如果你想在 doInBackground 方法中显示 toast,那么你必须在 UI 线程中编写你的 Toast 逻辑

          看看下面的答案链接 https://stackoverflow.com/a/11797945/582571

          但不建议在非ui线程下进行UI操作

          【讨论】:

            【解决方案7】:

            我们可以通过将接口传递给 AsyncTask 类并在 onPostExecute 方法中进行回调来做到这一点。

            public interface IResult {
                void onSuccess(String result);
                void onError(String error);                                                  
            }
            
            public static class AsyncTaskClass extends AsyncTask<String, String, Boolean> {
            
                IResult iResult;
            
                AsyncTaskClass(IResult iResult){
                    this.iResult = iResult;
                }
            
                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
                }
            
                @Override
                protected Boolean doInBackground(String... params) {
                    boolean result;
                    try {
                        //doing BackGround Operation Here
                        result = true;
            
                    } catch (Exception e) {
                        Log.e(TAG,"Error: " + e.getMessage());
                        result = false;
                    }
            
                   return result;
                }
            
                @Override
                protected void onPostExecute(Boolean success) {
                    super.onPostExecute(success);
                    Log.w(TAG, "On Post Execute: " + success);
                    if(success)
                        iResult.onSuccess("AsyncTask done successfully.");
                    else
                        iResult.onSuccess("Sorry! something went wrong.");
            
                }
            }                                                                      
              IResult iResult = new IResult() {
                  @Override
                  public void onSuccess(String result) {
                      Toast.makeText(PostActivity.this, result, Toast.LENGTH_LONG).show();
                  }
            
                  @Override
                  public void onError(String error) {
                      Toast.makeText(PostActivity.this, error, Toast.LENGTH_LONG).show();
                  }
              };
              String param1 = "some value 1";
              String param2 = "some value 2";
            
              new AsyncTaskClass(iResult).execute(param1, param2);`
            

            【讨论】:

              【解决方案8】:

              使用 SDK 29

              public class LoginControl extends AsyncTask<String, Void, String> {
                  private final Context context;
              
                  public LoginControl (Context context) {
                      this.context = context;
                  }
                  
                  @Override
                  protected String doInBackground(String... strings) {
                   //do something
                  }
              
                  @Override
                  protected void onPostExecute(TokenBean tokenBean) {
                     Toast.makeText(context, "hello Toast", Toast.LENGTH_SHORT).show();
                  }
              }
              

              在 MainActivity.class 中

                  @Override
                  protected void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
                      setContentView(R.layout.activity_main);
                      String url="something";
                      Context context = getApplicationContext();
                      new LoginControl(context).execute(url);
                  }
              

              【讨论】:

                猜你喜欢
                • 2014-12-01
                • 2014-05-25
                • 2014-05-23
                • 2012-11-27
                • 1970-01-01
                • 2011-03-30
                • 1970-01-01
                • 2014-09-15
                • 1970-01-01
                相关资源
                最近更新 更多