私は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();
}
}
私は非UIスレッドからトーストを作成することはできないと思います。 runOnUiThread()を試してみてください – Skynet
これを試してみますが、これは私が見ている振る舞いと一貫していないようです。なぜならwhile(true)ループをコメントアウトすると、このスレッドのクラスからすべてのToastメッセージが見えるからです。 – Cody
これは問題ではないことを確認しました。 – Cody