如何在Android AsyncTask中显示Toast?

19

我正在尝试在继承了 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。

在doInBackground()方法中,您不能执行任何与UI相关的操作,请尝试在PostExecute()方法中显示您的Toast。 - Anupam
实际上,我正在从URL下载一些数据,我有四个URL,我想在每个URL下载完成后显示toast。如果我在post中这样做,它将无法逐个显示,只会显示最终结果。 - Nomiluks
8个回答

30

你不能在后台线程上更新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)中显示Toast。

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

为了清晰起见,请检查下面链接中的4个步骤主题。

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


22
创建一个处理器对象,并使用该对象执行所有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(); 
        }
    });
  }

1
关于上下文呢? - alireza
如果你对context.getMainLooper()感到困惑,可以尝试使用Looper.getMainLooper()来帮助你。 - Naveen Niraula

4
这是另一种未在下文中提到的方式:
第一步:将“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
        }
    }
  };
}

第三步: 现在,您可以通过调用以下代码的方式在代码中任何地方调用该处理程序:
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");

    }
};

2
在非UI线程(例如在后台执行)中无法显示Toast。您可以尝试使用标志的概念。
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();
        }


}

开心编码..!!!


2
在onPostExecute或onPreExecute中显示您的Toast。doInBackground在单独的线程上运行,但其他两种方法在UI线程上运行。
但是,如果必须在doInBackground中显示toast,那么可以使用Handler.postrunonUiThread来执行toast显示。

0

您正在尝试在非 UI 线程中显示 Toast,这就是为什么会出现此错误。

如果您想在 doInBackground 方法中显示 Toast,则必须在 UI 线程中编写 Toast 逻辑。

请查看下面的答案链接 https://dev59.com/n2gt5IYBdhLWcg3w0wvB#11797945

但是,在非 UI 线程下进行 UI 操作是不可取的


0

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

0
我们可以通过将接口传递给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);`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接