Ich versuche, das Verhalten von Threads in meiner Android-App besser zu verstehen. Aus irgendeinem Grund, wenn ich while (true) in einem meiner Worker-Threads verwende, wird Code in der run-Methode dieses Threads, der VOR der while-Schleife (true) existiert, niemals ausgeführt. Um klar zu sein, ich bin mir nicht sicher, ob der Code (Toast-Nachrichten) tatsächlich nicht ausgeführt wird oder ob die Art und Weise, wie die Thread-Synchronisation vom Android-Betriebssystem gehandhabt wird, dazu führt, dass meine Toast-Nachrichten nicht angezeigt werden. Dieses Verhalten scheint eine Art Blockierung zu sein, aber ich kann nicht herausfinden, warum dies passiert.Android/Java Thread-Synchronisierung: while (true) {} verursacht Blockierung
Meine App verwendet 3 Threads: den UI-Thread (Standard/Hauptthread in einer Android-App), einen Thread zum unendlichen Lesen von Daten vom USB-Port des Geräts zur Laufzeit und einen Thread zum Verarbeiten dieser Daten über Nachrichten vom USB -Lesesthread. Das Problem scheint in meiner USBController-Klasse aufzutreten. Wenn ich meine unendliche while-Schleife auskommentiere, werden alle Toast-Nachrichten vor dem Start der Schleife gut angezeigt. Wenn ich meine Weile nicht auskommen lasse (wahr), KEINE TOASTMELDUNGEN EVER DISPLAY! Ich bin ziemlich verwirrt, ich glaube, ich missverstände etwas Grundlegendes über die Thread-Handhabung durch das Android OS. Selbst wenn eine while-Schleife eine Blockierung verursachen würde, was ich nicht glaube, da sie sich in einem Worker-Thread befindet, warum würden die Toast-Nachrichten, die vor der while-Schleife auftreten, nicht ausgelöst werden, ? Ist das ein Synchronisationsproblem? Verwende ich das Handler-Looper-System von Android?
Code unten. Hinweis: Ich habe den relevanten Teil der Hauptaktivität und die gesamte USBController-Klasse hinzugefügt. Meine Implementierung dieser Klasse hängt stark von der USB-zu-Seriell-Bibliothek ab, die hier gefunden wird mik3y/usb-serial-for-android. Ich denke nicht, dass es notwendig ist, aber ich habe die Klasse, die meinen dritten Thread enthält, SensorDataBuffer, der Nachrichten vom Thread UsbController empfängt, aufgenommen.
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();
}
}
Ich denke, Sie können keinen Toast von einem Nicht-Ui-Thread erstellen. Versuchen Sie es mit runOnUiThread() – Skynet
Ich werde versuchen, aber das scheint nicht mit dem Verhalten, das ich sehe, weil, wenn ich die while (true) Schleife kommentieren ich sehe alle Toast-Nachrichten aus diesem Thread-Klasse. – Cody
Bestätigt, dass dies nicht das Problem ist. – Cody