2014-03-24 47 views
0

在我的代码中,只要我的ToggleButton被选中,我必须发送一条消息。为了防止UI线程冻结,我把这个动作放在一个单独的线程中。此线程为什么会冻结用户界面

我的问题是,它仍然冻结,但我不知道为什么

这是相关代码:

private ToggleButton.OnClickListener lightMirrorOnClickListener = new ToggleButton.OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     if (lightMirrorBtn.isChecked()) { 
      lightThread = new LightThread(); 
      lightThread.start(); 
     } else if(!lightMirrorBtn.isChecked()) { 
      lightThread.interrupt(); 
     } 
    } 

}; 

class LightThread extends Thread { 

    Handler lightHandler = new Handler(); 

    Runnable light = new Runnable() { 
     public void run() { 

      while (lightMirrorBtn.isChecked()) { 
       lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME; 
       lightTxMsg.frameType = ConstantList.DATA_FRAME; 
       lightTxMsg.dataLength = (byte) 8; 
       lightTxMsg.messageID = 0x3C1; 
       int[] messageArray = AMBI_LIGHT; 
       for (int i = 0; i < lightTxMsg.dataLength; i++) { 
        lightTxMsg.data[i] = messageArray[i]; 
       } 

       returnCode = demoController.transmitMessage(lightTxMsg, 
         ConstantList.BINARY_FORMAT);  
      } 
     } 
    }; 

    public void run() { 
     while (!isInterrupted()) { 
      try { 
       Thread.sleep(60); 
       lightHandler.post(light); 

      } catch (InterruptedException e) { 
       break; 
      } 
     } 

    } 

} 

编辑: 这是该问题的解决方案:

private ToggleButton.OnCheckedChangeListener lightMirrorOnClickListener = new ToggleButton.OnCheckedChangeListener() { 

    @Override 
    public void onCheckedChanged(CompoundButton buttonView, 
      boolean isChecked) { 
     if (isChecked == true) { 
      new Thread(new Runnable() { 
       public void run() { 
        lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME; 
        lightTxMsg.frameType = ConstantList.DATA_FRAME; 
        lightTxMsg.dataLength = (byte) 8; 
        lightTxMsg.messageID = 0x3C1; 
        int[] messageArray = AMBI_LIGHT_ON; 
        for (int i = 0; i < lightTxMsg.dataLength; i++) { 
         lightTxMsg.data[i] = messageArray[i]; 
        } 

        returnCode = demoController.transmitMessage(lightTxMsg, 
          ConstantList.BINARY_FORMAT); 
       } 
      }).start(); 

     } else if (!isChecked) { 
      new Thread(new Runnable() { 
       public void run() { 
        lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME; 
        lightTxMsg.frameType = ConstantList.DATA_FRAME; 
        lightTxMsg.dataLength = (byte) 8; 
        lightTxMsg.messageID = 0x3C1; 
        int[] messageArray = AMBI_LIGHT_OFF; 
        for (int i = 0; i < lightTxMsg.dataLength; i++) { 
         lightTxMsg.data[i] = messageArray[i]; 
        } 

        returnCode = demoController.transmitMessage(lightTxMsg, 
          ConstantList.BINARY_FORMAT); 
       } 
      }).start(); 
     } 
    } 

}; 
+0

我建议你查一下有关使用Java多线程的一些教程,你在那里有几次失误。例如,扩展Thread并在其内部创建一个Runnable是多余的,一个线程已经是一个Runnable。 – m0skit0

+0

你可能会说出其中的一些,所以它更容易做研究? – Fraggles

+0

对不起,这不是一个学习的地方,但要提出具体问题。你甚至不应该尝试写多线程代码,而不必先阅读它。我可以指向[Oracle的官方教程](http://docs.oracle.com/javase/tutorial/essential/concurrency/),它们是一个很好的开始。 – m0skit0

回答

3
Handler lightHandler = new Handler(); 

当你CREA你的处理程序你的线程尚未开始。它刚刚创建。因此,根据Handlerdefault constructor documentation,此处理程序与“当前线程的Looper”关联......这是当前主要(UI)线程。所以你在主线程上发布消息。

你不需要Handler来发布你的runnable。您可以:

  1. 创建一个线程,并指定它在run()方法操作 或
  2. 使用Thread(Runnable)构造函数传递一个Runnable到你的线程将在你的线程执行

这里是关于Threads的基本文章:

  1. Processes and threads
  2. Keeping your app responsive
  3. Specifying the Code to Run on a Thread
+0

好信息,thx!但我想知道,为什么这只是这个线程上的问题。在所有其他线程中,我在同一位置创建了一个新的Handler对象 – Fraggles

+0

我不知道您的其他线程在做什么。这一个有一个循环,while while lightMirrorBtn.isChecked()。它也睡了60毫秒。在其他线程中是否有这些长时间运行的动作?你确定它们(和它们的处理程序)是否也在UI线程中创建(例如,在onClick中)? – stan0

+0

我不认为这是问题。一个'Handler'只能在UIThread(主线程)或者调用了'Looper.prepare()'的线程中实例化,这个AFAIK你不能手动调用。不,'Handler#post'(和家人)不会在UIThread中运行。 – m0skit0