【问题标题】:Can't create handler inside thread that has not called Looper.prepare()无法在未调用 Looper.prepare() 的线程内创建处理程序
【发布时间】:2011-09-06 23:57:32
【问题描述】:

我收到此错误“无法在未调用 Looper.prepare() 的线程内创建处理程序”

你能告诉我如何解决它吗?

public class PaymentActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.payment);

    final Button buttonBank = (Button) findViewById(R.id.buttonBank);

    buttonBank.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            progressDialog = ProgressDialog.show(PaymentActivity.this, "",
                    "Redirecting to payment gateway...", true, true);

            new Thread() {
                public void run() {
                    try {
                        startPayment("Bank");
                    } catch (Exception e) {
                        alertDialog.setMessage(e.getMessage());
                        handler.sendEmptyMessage(1);
                        progressDialog.cancel();
                    }
                }
            }.start();
        }

    });

开始付款方式:

    private void startPayment(String id) {
    Bundle b = getIntent().getExtras();
    final Sail sail = b.getParcelable(Constant.SAIL);

    final Intent bankIntent = new Intent(this, BankActivity.class);

    try {
        Reservation reservation = RestService.createReservation(
                sail.getId(),
                getSharedPreferences(Constant.PREF_NAME_CONTACT, 0));
        bankIntent.putExtra(Constant.RESERVATION, reservation);

        // <workingWithDB> Storing Reservation info in Database
        DBAdapter db = new DBAdapter(this);
        db.open();
        @SuppressWarnings("unused")
        long rowid;
        rowid = db.insertRow(sail.getId(), sail.getFrom(),
                sail.getTo(), sail.getShip(), sail.getDateFrom().getTime(),
                sail.getPrice().toString(), reservation.getId().floatValue());
        db.close();
        // </workingWithDB>

        String html = PaymentService.getRedirectHTML(id, reservation);

        bankIntent.putExtra(Constant.BANK, html);
    } catch (Exception e) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        AlertDialog alertDialog = builder.create();
        alertDialog.setMessage(e.getMessage());
        alertDialog.show();
    }

    startActivity(bankIntent);
}

【问题讨论】:

  • 请贴出startPayment()方法代码。

标签: java android handler


【解决方案1】:

你应该知道,当你尝试修改你的 UI 时,唯一线程可以做到这一点是UiThread

所以如果你想在另一个线程中修改你的 UI,尝试使用方法:Activity.runOnUiThread(new Runnable);

你的代码应该是这样的:

 new Thread() {
    public void run() {  
        YourActivity.this.runOnUiThread(new Runnable(){

             @Override
             public void run(){
                 try {
                      startPayment("Bank");//Edit,integrate this on the runOnUiThread
                 } catch (Exception e) {
                     alertDialog.setMessage(e.getMessage());
                     handler.sendEmptyMessage(1);
                     progressDialog.cancel();
                 } 
            });                
           }
      }
  }.start();

【讨论】:

    【解决方案2】:

    我假设您在 startPayment() 方法中创建了一个处理程序。您不能这样做,因为只能在 UI 线程上创建处理程序。只需在您的活动类中创建它即可。

    【讨论】:

      【解决方案3】:

      而不是new Thread() 行,尝试给予

      this.runOnUiThread(new Runnable() {
      

      【讨论】:

        【解决方案4】:

        您无法更改线程中的任何 UI,您可以使用 runOnUIThreadAsyncTask 了解有关此 click here 的更多详细信息

        【讨论】:

          【解决方案5】:

          我发现大多数线程处理都可以用这样的 AsyncTasks 代替:

          public class TestStuff extends Activity {
              @Override
              public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.main);
          
                  Button buttonBank = (Button) findViewById(R.id.button);
                  buttonBank.setOnClickListener(new View.OnClickListener() {
                      public void onClick(View v) {
                          new StartPaymentAsyncTask(TestStuff.this).execute((Void []) null);
                      }
                  });
              }
          
              private class StartPaymentAsyncTask extends AsyncTask<Void, Void, String> {
                  private ProgressDialog dialog;
                  private final Context context;
          
                  public StartPaymentAsyncTask(Context context) {
                      this.context = context;
                  }
          
                  @Override
                  protected void onPreExecute() {
                      dialog = new ProgressDialog(context);
                      // setup your dialog here
                      dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                      dialog.setMessage(context.getString(R.string.doing_db_work));
                      dialog.setCancelable(false);
                      dialog.show();
                  }
          
                  @Override
                  protected String doInBackground(Void... ignored) {
                      String returnMessage = null;
                      try {
                          startPayment("Bank");
                      } catch (Exception e) {
                          returnMessage = e.getMessage();
                      }
                      return returnMessage;
                  }
          
                  @Override
                  protected void onPostExecute(String message) {
                      dialog.dismiss();
                      if (message != null) {
                          // process the error (show alert etc)
                          Log.e("StartPaymentAsyncTask", String.format("I received an error: %s", message));
                      } else {
                          Log.i("StartPaymentAsyncTask", "No problems");
                      }
                  }
              }
          
              public void startPayment(String string) throws Exception {
                  SystemClock.sleep(2000); // pause for 2 seconds for dialog
                  Log.i("PaymentStuff", "I am pretending to do some work");
                  throw new Exception("Oh dear, database error");
              }
          }
          

          我将应用程序上下文传递给异步,以便它可以从中创建对话框。

          这样做的好处是您可以准确地知道哪些方法在您的 UI 中运行,哪些在单独的后台线程中。您的主 UI 线程没有延迟,并且分离成小的异步任务非常好。

          代码假定您的 startPayment() 方法对 UI 没有任何作用,如果有,请将其移至 AsyncTask 的 onPostExecute 中,以便在 UI 线程中完成。

          【讨论】:

          • 我在“new StartPaymentAsyncTask(this).execute((Void []) null) }”中收到此错误错误 - 构造函数 PaymentActivity.StartPaymentAsyncTask(new View.OnClickListener(){}) 未定义
          • 是的,this 应该是 YourActivity.this。我已经更新了代码(我认为应该是 PaymentActivity)
          • 断点 onClick 方法和异步任务的构造函数以查看它们是否正常工作(或添加日志记录)。您是否为进度对话框添加了所有设置?我在上面添加了示例代码。
          • 我已将代码修改为完全工人阶级。如果您使用的是 eclipse,您需要做的就是在默认的 android 应用程序中添加一个带有 id 为“button”的按钮,以使其正常工作。如果你注释掉最后抛出的异常,你会得到“没有问题”的消息
          • 您尝试了整个课程,还是只是将您需要的代码插入到代码中?修改后的代码应该显示一个微调器 2 秒(你看到了吗?),然后在日志中你应该看到 startPayment() 方法中的“我正在假装做事”,然后是错误消息,再次出现在日志中。
          【解决方案6】:

          试试

          final Handler handlerTimer = new Handler(Looper.getMainLooper());
                  handlerTimer.postDelayed(new Runnable() {
                      public void run() {
                                          ...... 
          
                                        }
                                                           }, time_interval});
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-08-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多