2016-06-01 8 views
1

私はAndroidアプリケーションのスレッドの動作をよりよく理解しようとしています。何らかの理由で、ワーカースレッドのwhile(true)を使用すると、while(true)ループが実行される前に、そのスレッドのrunメソッド内のコードが順番に存在します。明確にするために、コード(トーストメッセージ)が実際に実行されていないかどうか、またはスレッド同期がAndroid OSによって処理される方法によって私のToastメッセージが表示されない場合はわかりません。この現象は何らかのブロックのように見えますが、なぜこのようなことが起こるのか理解できません。Android/Javaスレッド同期:while(true){}が原因でブロックされます

私のアプリでは、UIスレッド(Androidアプリケーションのデフォルト/メインスレッド)、実行時にデバイスのUSBポートからデータを無限に読み取るスレッド、USBからのメッセージでこのデータを処理するスレッド読んだスレッド。問題は私のUSBControllerクラスで発生するようです。無限のwhileループをコメントアウトすると、ループの開始前にすべてのToastメッセージが正常に表示されます。 私の中にコメントしていないとき(本当)、TOASTのメッセージは表示されません!私はこれでかなり混乱していますが、私はAndroid OSのスレッド処理に関する基本的な何かを誤解していると思います。たとえwhileループがブロックを引き起こしたとしても、それはワーカースレッドにあるので考えられません。whileループの前に発生するトーストメッセージはなぜトリガーされませんか?これは同期の問題ですか? AndroidのHandler-Looperシステムを悪用していますか?

以下のコード。注:主なアクティビティの関連部分とUSBControllerクラスの全体を含めました。このクラスの私の実装は、ここにあるmik3y/usb-serial-for-androidにあるUSB to Serialライブラリに大きく依存しています。私はそれが必要ではないと思うが、私はスレッドUsbControllerからのメッセージを受け取る3番目のスレッド、SensorDataBufferを含むクラスをインクルードしました。

UsbController.java

public class UsbController extends Thread{ 
    ... 
    @Override 
    public void run() { 
     android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT); //sets thread to default queing priority 
     Looper.prepare(); 
     Toast.makeText(mContext.getApplicationContext(), "Hello from UsbController's run method!", Toast.LENGTH_SHORT).show(); 

     // **********************USB otg******************************* 
     //Obtain permission to use Android device's USB intent 
     PendingIntent mPermissionIntent; 
     mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 

     // Find all available drivers from attached devices. 
     ProbeTable customTable = new ProbeTable(); 
     customTable.addProduct(0x03EB, 0x2044, CdcAcmSerialDriver.class);     
     UsbManager manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); 
     UsbSerialProber prober = new UsbSerialProber(customTable); 
     List<UsbSerialDriver> availableDrivers = prober.findAllDrivers(manager); 

     if (availableDrivers.isEmpty()) { 
      Toast.makeText(mContext.getApplicationContext(), "No available USB drivers found",Toast.LENGTH_SHORT).show(); // Toast message for debugging 
     } 
     else {             // open connection to first avail. driver 
      UsbSerialDriver driver = availableDrivers.get(0); 
      Toast.makeText(mContext.getApplicationContext(), "Driver found",Toast.LENGTH_SHORT).show(); // Toast message for debugging 
      UsbDeviceConnection connection = manager.openDevice(driver.getDevice()); 
      Toast.makeText(mContext.getApplicationContext(), "Device Driver Opened",Toast.LENGTH_SHORT).show(); // Toast message for debugging 
      if (connection == null) {   // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..) 
       Toast.makeText(mContext.getApplicationContext(),"Connection to device not allowed, need permissions",Toast.LENGTH_LONG).show(); 
       manager.requestPermission(driver.getDevice(),mPermissionIntent); //conn test 
       if (manager.hasPermission(driver.getDevice())==true){ 
        Toast.makeText(mContext.getApplicationContext(),"Permissions granted",Toast.LENGTH_SHORT).show(); 
       } 
      } 
      else {      // Read some data! Most have just one port (port 0). 
       List<UsbSerialPort> myPortList = driver.getPorts(); 
       UsbSerialPort port = myPortList.get(0); 
       Toast.makeText(mContext.getApplicationContext(),"USB OTG Connection Established",Toast.LENGTH_SHORT).show(); 
       try { 
        port.open(connection); 
        port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // sets baud rate,databits, stopbits, & parity 
        port.setDTR(true);     //necessary to make Arduino Micro begin running it's program 
        Toast.makeText(mContext.getApplicationContext(),"port opened, parameters set, DTR set",Toast.LENGTH_SHORT).show(); 
        byte buffer[] = new byte[16];  
        String incompPacket = ""; 
        Toast.makeText(mContext.getApplicationContext(), "hi again!"), Toast.LENGTH_LONG).show(); 
        while (true){     //continuous loop to read data 
         numBytesRead = port.read(buffer, 100);   
         arduinoData = new String(buffer, "US-ASCII"); 
         String raw = arduinoData.substring(0, numBytesRead); 
         if (numBytesRead > 0) { 
          ... 
         } 
        } 
       } catch (IOException e) { 
        Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show(); 
       } 
      } 
     } 
     Looper.loop(); 
    } 
} 

MainActivity.java

... 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 

     //Multi-threading 
     //Create thread to handle incoming data from USB Controller thread 
     SensorDataBuffer pressureDataBuffer = new SensorDataBuffer(MainActivity.this); 
     Thread bufferThread = new Thread(pressureDataBuffer); 
     bufferThread.start(); 

     //Create USB Serial Worker thread which will continuously receive data 
     UsbController serialDataLink = new UsbController(PlayFrets.this); 
     Thread sensorMonitorThread = new Thread(serialDataLink); 
     sensorMonitorThread.start(); 
     //Toast.makeText(this, "USB Controller thread started", Toast.LENGTH_SHORT).show(); 

     //Build GUI 
     super.onCreate(savedInstanceState); 
     requestWindowFeature(Window.FEATURE_NO_TITLE);   //Removes action bar from display 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //Removes status bar from display 

     //Create AsyncTask to load the note files. A splash screen will be displayed while task is executing 
     new AsyncTask_NoteFileLoader(this).execute(); 
     } 
... 

SensorDataBuffer.java

public class SensorDataBuffer extends Thread{ 

    //Handler subclass which accepts messages one by one in 
    //the main activitiy's FIFO message que called a "Looper" 
    //The worker thread, sensorMonitor, runs UsbController in parallel 
    //with the UI thread and continuously formats and sends pressure sensor 
    //values read from the microcontroller to the Handler which updates the 
    //corresponding pressure state logic variables in the UI thread. 
    public void run(){ 
     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); //TODO:priority was previously more favorable, test this to ensure UI doesn't lag 
     Looper.prepare(); //create MessageQue to receive messages from USB Controller thread 
     UsbController.setHandler(bufferHandler); 

     bufferHandler = new Handler(Looper.myLooper()) { 
       //do stuff 
     }; 
     Looper.loop(); 
    } 
} 
+2

私は非UIスレッドからトーストを作成することはできないと思います。 runOnUiThread()を試してみてください – Skynet

+0

これを試してみますが、これは私が見ている振る舞いと一貫していないようです。なぜならwhile(true)ループをコメントアウトすると、このスレッドのクラスからすべてのToastメッセージが見えるからです。 – Cody

+0

これは問題ではないことを確認しました。 – Cody

答えて

0

HandlerThreads、Handlers、Runnablesを代わりに使うのはどうですか?あなたのコードをよりクリーンで保守しやすくします。あなたのonCreateで

()ちょうどそれらのカップルを作成します。

HandlerThread usbThread = new HandlerThread("USBController"); 
usbThread.start(); 
usbHandler = new Handler(usbThread.getLooper()); 

HandlerThread sensorThread = new HandlerThread("SensorDataBuffer"); 
sensorThread.start(); 
sensorHandler = new Handler(sensorThread.getLooper()); 

次に、あなたがあなたのランナブルを作成し、実行可能なポスト自体を聞かせて、それができハンドラに

usbHandler.post(new Runnable(){ 
    run(){ 
     //.... 
     numBytesRead = port.read(buffer, 100); 
      if (numBytesRead > 0) { 
       sensorHandler.post(new Runnable(){run(){//doSomething}}); 
      } 
     //.... 
     if(isStillRunning) 
      usbHandler.post(this); 
    } 
}); 

それらを投稿永遠に走ります。その中から、メインスレッドハンドラのような他のハンドラにランナブルを投稿してトーストを表示することができます。

+0

ああ、匿名のrunnablesを使用する代わりに、コンストラクタで開始してrun()メソッドを無限ループとして使用するのに必要なすべてのものを行う独自のものを持つことができます – xxtesaxx

+0

これはコードをよりクリーンにしません私は今onCreate()メソッドに大きな不安を抱えているので、維持するのは難しいですか?私は自分のコードがかなり読みやすいと思っていました。それぞれのスレッドはそれぞれ独自のクラスと.javaファイル – Cody

関連する問題