Android/Java Thread sync: while(true){} causing blocking - java

I'm trying to better understand the behavior of threads in my android app. For some reason, when I use while(true) in one of my worker threads, code within that thread's run method that exists sequentially BEFORE the while(true) loop never executes. To be clear, I'm not sure if the code(toast messages) actually isn't executing or if the way the thread synchronization is handled by the Android OS is causing my Toast messages not to display. This behavior appears to be some sort of blocking but I can't figure out why this happens.
My app uses 3 threads: the UI thread(default/main thread in an Android app), a thread to infinitely read data from the device's USB port during runtime, and a thread to process this data via messages from the USB-read thread. The problem seems to occur in my USBController class. When I comment out my infinite while loop, all of the Toast messages before the start of the loop display just fine. When I don't comment out my while(true), NO TOAST MESSAGES EVER DISPLAY! I'm pretty confused by this, I think i'm misunderstanding something fundamental about thread handling by the Android OS. Even if a while loop were to cause blocking, which i don't think it since it resides in a worker thread, why wouldn't the toast messages that occur before the while loop be triggered? Is this a synchronization issue? Am I misusing Android's Handler-Looper system?
Code below. Note: I've included the relevant portion of the main activity and the entirety of the USBController class. My implementation of this class relies heavily on the USB to Serial library found here mik3y/usb-serial-for-android. I don't think it's necessary, but i've included the class that contains my third thread, SensorDataBuffer, that receives messages from the thread UsbController.
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();
}
}

How about using HandlerThreads, Handlers and Runnables instead? Makes your code a lot cleaner and easier to maintain.
In your onCreate() just create a couple of them:
HandlerThread usbThread = new HandlerThread("USBController");
usbThread.start();
usbHandler = new Handler(usbThread.getLooper());
HandlerThread sensorThread = new HandlerThread("SensorDataBuffer");
sensorThread.start();
sensorHandler = new Handler(sensorThread.getLooper());
Then you create your Runnables and post them to the Handlers
usbHandler.post(new Runnable(){
run(){
//....
numBytesRead = port.read(buffer, 100);
if (numBytesRead > 0) {
sensorHandler.post(new Runnable(){run(){//doSomething}});
}
//....
if(isStillRunning)
usbHandler.post(this);
}
});
You can let the runnable post itself and it will run forever. From within you can post runnables to other handlers (like the Main Thread Handler) to show your Toasts.

Related

Fail whe i try to connect my app to webServices

Actully i working in a app, but i have problems to connect my Web services, i have this code:
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
System.out.println("Si lo mande///////////////////Jhgfdsa");
String respuesta = post.getRespueta();
System.out.println(respuesta);
Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
but i can make connection, i try to make other thinks, but i can make the thread, i'am new in this part, the app launcher this error:
android os network on main thread exception
It is not okay to do the Network Operation on main thread.. You can use AsyncTask to perform such operations and handle the result in onPostExecute method.
class YourNetworkingTasks extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
String respuesta = post.getRespueta();
Log.d("Output", respuesta);
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
return null;
}
protected void onPostExecute(RSSFeed feed) {
// TODO: YOU CAN MAKE U.I. Changes Like Display text in TextView, TOAST HERE.
// TODO: do something with the result
}
}
And write new YourNetworkingTasks().execute(); to run that code in background thread.
Please also not that since you are using http and not https you may get Network Security Exception and may not get any output due to recent security change in android.

The screen freezes till the function returns

i need to use a code to check if i have internet access before i push files to the database ..
this is the code i am using. it works fine if i have internet connection but if not it freezes for like 6 or 7 seconds
public static boolean isInternetReachable() throws InterruptedException, IOException {
Process p1 = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
int returnVal = p1.waitFor();
return (returnVal==0);
}
i want it to push files - file by file - to database and i want to check if the internet is working or not everytime
To check if a user is connected to the internet, use this.
public boolean hasInternetConnection() {
ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return manager.getActiveNetworkInfo() != null && manager.getActiveNetworkInfo().isConnected();
}
Your screen freezes because you're performing a long running task (uploading files) on the main thread which can lead to your app not being responsive. You'll have to move that operation off the main thread, either by using an AsyncTask, RxJava, or Coroutines (Kotlin).
See this
Handler hander = new Handler(this);
handler.postDelayed(new Runnable() {
#Override
public void run() {
//do what you want
},2000L);

How to use mediaPlayer correctlty?

I'm trying to play music in my app and while the media player is loading I want to allow the user to keep on using the app, but the app gets stuck for few seconds every time I start loading the media player, and when the media player is finished loading, only then the app returns to normal and starts working again, sometimes it's not just freezing, it also shows popup menu from the OS that prompts the user to quit the app.
I couldn't find any solution in Google or YouTube, anyone knows what's wrong with my code?
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
String STREAM_URL = #####; // here i put the URL of the song
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(STREAM_URL);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
} catch (NullPointerException e) {
Log.d(TAG, "run: NullPointerException = " + e.getMessage());
FirebaseCrash.log("Tag = " + TAG + "run: NullPointerException = " + e.getMessage());
}
}
}
};
handler.post(runnable);
Even though you are creating a Handler, the creation of the MediaPlayer still happens on the main UI thread. You should call prepareAsync or use an AsyncTask or some other means to avoid calling prepare on the main thread.
From the documentation for Handler:
When you create a new Handler, it is bound to the thread / message
queue of the thread that is creating it
If you are streaming music from the network, preparing the media for playback is especially going to take a while. One option may be to call prepareAsync instead of calling prepare. In that case, you should set the OnPreparedListener, and in that callback call start.

executeDispatch synchronous?

I'm working on a java Applet which has a document loaded. On this Applet I have a custom "print" button which basically inits the print process of the document. This is the code that is executed after this button is pressed:
PropertyValue[] printProperties = new PropertyValue[1];
printProperties[0] = new PropertyValue();
printProperties[0].Name = "Print";
printProperties[0].Value = new Boolean(true);
xDispatchProvider = (XDispatchProvider)UnoRuntime.queryInterface (XDispatchProvider.class, xFrame);
dispatcher.executeDispatch(xDispatchProvider, ".uno:Print","_self", 0, printProperties);
someOtherProcess();
This code opens the native(?) print dialog which is the expected behaviour, and works so far. The problem is the "someOtherProcess" method. I need to execute this method right after the print dialog is closed either by pressing its "print" button or canceling/closing the print dialog.
Since executeDispatch is async I tried to make it synchronous using the "SynchronMode" in the PropertyValue[] with no success.
I found a way to listen to print events which are fired when the print process starts or when it's cancelled. This is the whole code:
PropertyValue[] printProperties = new PropertyValue[1];
printProperties[0] = new PropertyValue();
printProperties[0].Name = "Print";
printProperties[0].Value = new Boolean(true);
xDispatchProvider = (XDispatchProvider)UnoRuntime.queryInterface (XDispatchProvider.class, xFrame);
dispatcher.executeDispatch(xDispatchProvider, ".uno:Print","_self", 0, printProperties);
XPrintJobBroadcaster xPrintJobBroadcaster = (XPrintJobBroadcaster)UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xComponent);
xPrintJobBroadcaster.addPrintJobListener(new MyPrintJobListener());
class MyPrintJobListener implements XPrintJobListener {
public void printJobEvent(PrintJobEvent printJobEvent) {
AppletLogger.log("printing");
}
public void disposing(com.sun.star.lang.EventObject eventObject) {
AppletLogger.log("disposing");
}
}
The "printJobEvent" is fired when the print process has either started, finished, cancelled and so on, but I can't find a way to know if the print dialog has been cancelled or closed as this doesn't fire any print event.
So my main questions are, is there a way to open a print dialog in a synchronous way so that the programs waits for the print dialog to close?
Is there a way to listen to the close event of the native print dialog window?
Thanks in advance!
Check the State property. If printing is cancelled, it should first show JOB_STARTED (which is 0) and then JOB_ABORTED (which is 3).
class MyPrintJobListener implements XPrintJobListener {
public void printJobEvent(PrintJobEvent printJobEvent) {
AppletLogger.log("print status: " + printJobEvent.State.getValue());
}
public void disposing(com.sun.star.lang.EventObject eventObject) {
AppletLogger.log("disposing");
}
}
Also the dispatcher didn't work for me. Use the API interface instead:
XPrintJobBroadcaster xPrintJobBroadcaster = (XPrintJobBroadcaster)
UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xComponent);
xPrintJobBroadcaster.addPrintJobListener(new MyPrintJobListener());
XPrintable xPrintable =
(XPrintable)UnoRuntime.queryInterface(XPrintable.class, xComponent);
xPrintable.print(printProperties);
try { Thread.sleep(10000); } catch (Exception e) {} // Wait for print job.

Do action while reading big files java

I'm making a chat program with Java, and I'm doing the communication through TCP and serializable objects. The chat can exchange files, too, but when the files are too big (video files) the interface freezes until it completes the file loading and object transmition process. I need to show a message while the file is being loaded. This is my code:
File file = jFileChooser1.getSelectedFile();
String name= fichero.getName();
int size = (int)fichero.length();
byte[] byteArray = new byte[size];
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(byteArray);
} catch (IOException ex) {
Logger.getLogger(Explorador.class.getName()).log(Level.SEVERE, null, ex);
}
I need to show a message while this line "bis.read(byteArray);" is reading, since I believe that line is the reason the interface freezes.
After the byteArray is loaded I put it on a object and send it through the socket connection.
I also need a video streaming, not live, just to open a video file on the server and send it by pieces to the connected clients and play it. Can anyone give me tutorials or tips? thanks.
That UI freezing indicates that you are blocking Swing's Event Dispatch Thread. You want to perform all time-consuming tasks explicitly in other threads instead. One simpler way is to use SwingWorker.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
You can put your code in a Thread and code a method waiting for it to complete.
new Thread(new Runnable() {
#Override
public void run() {
//Code here
}
}).start();
You can perform your tasks in a thread:
new Thread(new Runnable() {
#Override
public void run() {
//Code here
}
}).start();
And use runlater() to update your view.

Categories