无法在未调用 Looper.prepare() 的线程内创建处理程序

Posted

技术标签:

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

我收到此错误“”

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

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()方法代码。 【参考方案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);

【讨论】:

以上是关于无法在未调用 Looper.prepare() 的线程内创建处理程序的主要内容,如果未能解决你的问题,请参考以下文章

无法在未调用 Looper.prepare() 的线程内创建处理程序

无法在未调用 Looper.prepare() 的线程内创建处理程序

无法在未调用 Looper.prepare()-Alertdialogbox 的线程内创建处理程序 [重复]

无法在未调用 Looper.prepare() Graphhopper 的线程内创建处理程序

原因:无法在未调用 Looper.prepare() 的线程上敬酒

运行时异常“无法在未调用 looper.prepare() 的线程内创建处理程序”