Problems delaying the execution of a code in Android - android

I have implemented an app which can communicates with a metawear device through i2c communication. The problem I have right now is that after sending a write command I need to wait a certain amount of time until I read the values (around 150ms).
The problem I have is that it doesn't wait that specific time. I used TimeUnit, Thread.sleep and wait functions but still doesn't make the delay I want it to execute the next line of code. Here is the function that I have implemented:
#Override
protected void test_application(){
timerModule.scheduleTask(new Timer.Task() {
#Override
public void commands() {
i2cModule.writeData((byte) 0x34, (byte) 0xA0, new byte[]{(byte) 0x98});
//We need to wait >80ms for the ADC to finish the conversion value
// synchronized (this) {
// try {
// wait(150);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//}
try{
TimeUnit.MILLISECONDS.sleep(150);
} catch (InterruptedException e){
e.printStackTrace();
}
//try{
// Thread.currentThread().sleep(150);
//} catch (InterruptedException e){
// e.printStackTrace();
//};
//After waiting 150ms for the conversion time, we read the output value through the I2C line
i2cModule.readData((byte)0x34, (byte)0x00, (byte)4).onComplete(new CompletionHandler<byte[]>() {
#Override
public void success(byte[] result) {
auxvar = result;
}
});
finalvoltage = ((auxvar[0]&0x3F)<<18)|(auxvar[1]<<10)|(auxvar[2]<<2)|((auxvar[3]&0xC0));
diff_volt1 = (float)finalvoltage * 3/16777215;
LineData data = chart.getData();
if (startTime == -1) {
data.addXValue("0");
startTime= System.currentTimeMillis();
} else {
data.addXValue(String.format("%.2f", (System.currentTimeMillis() - startTime) / 1000.f));
}
data.addEntry(new Entry(diff_volt1, sampleCount), 0);
sampleCount++;
}
}, 500, false).onComplete(new AsyncOperation.CompletionHandler<Timer.Controller>() {
#Override
public void success(Timer.Controller result) {
result.start();
}
});
I want it to wait before executing the i2cmodule.readData() function. Here is the capture from the logic analyzer so that you could see that it doesn't wait before reading the data
Does anyone know how to implement this or solve this issue? Thanks anyway.
EDIT: I have changed the writing command to just one line and the new output of the logic analyzer is as follows:
byte[] hello = {(byte)0xA0, (byte)0x98};
i2cModule.writeData((byte) 0x34, (byte) 0x00, hello);
And the new output is at follows:

Generally it is a bad idea to 'wait' for a command to finish if it is asynchronous. You need to make sure that the .writeData() method is finished BEFORE you execute the .readData() method.
There are many ways to do this. I like the listener pattern, but for this you could also use an abstract class construction.
The basic idea is to implement a class (let's call this DataWriter) that invokes an abstract method as soon as the writing of the data is done.
A very basic example would be:
class definition
abstract class DataWriter {
public DataWriter() {
doWritingFunction();
}
private void doWritingFunction() {
//here you do your writing operation
//when it's done it calls:
onWritingDone();
}
abstract void onWritingDone();
}
Then you instantiate your class like this:
DataWriter dataWriter = new DataWriter() {
#Override
void onWritingDone() {
//do data read here
}
};
Never use Thread.sleep() to wait for an asynchronous task to finish, since you never know when it is going to be finished

Related

Running a different thread does not allow the activity to be displayed

I have this piece of an activity:
public class ResultActivity extends AppCompatActivity implements ResultListener {
private String code = "";
private String data = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
code = intent.getStringExtra("code");
data = intent.getStringExtra("data");
MyExternal.DecodeAndSend(this, code, data);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Where MyExternal is a class in other library.
The method DecodeAndSend is something like this:
public static boolean DecodeAndSend(ResultListener caller, String codigo, String data)
{
try {
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return true;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return false;
}
Finally, ServerConnection class implements Callable<String> so I show you the call method:
#Override
public String call() throws Exception {
Thread.sleep(2000);
return "OK";
}
The call to Thread.sleep(2000); is actually a call to a web server to send some data.
The problem is that the ResultActivity does not show its layout until the call call returns.
What is missing in this code?
DecodeAndSend is called from the main thread. It calls Future.get() which waits for the job to finish, so it's blocking the main thread. You should call this method from a background thread as well. I think it would be okay to send it to your same thread pool since it is submitted after the first job that it will wait for.
You cannot return anything about the request results from this method, because it is asynchronous.
public static void DecodeAndSend(ResultListener caller, String codigo, String data)
{
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
pool.submit(new Runnable() {
public void run () {
try {
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
caller.OnError(null); // No status, only an exception
});
}
However, your ServerConnection class already takes a caller parameter, so it should probably just handle the callback itself. And depending on what you're doing in the callback, you might want to post the callback calls to the main thread.
By the way, convention in Java is to always start method names with a lower-case letter (camel case).
Feature.get() is a blocking call. The UI Thread is blocked waiting for that call to return, hence can't take care of drawing your layout. Try passing the result listener to ResultListener to the ServerConnection and use the two callbacks to update your UI accordingly
Future.get() is a blocking call - execution stops until the result arrives
The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready.
So your Activity's onCreate method calls that stuff, and then blocks until call (which is running on another thread) returns its result. So onCreate doesn't finish, and the layout doesn't complete.
If you want to use that blocking code, but after the view has laid out, I'd use another part of the Activity lifecycle like onStart (set a flag so you only run it once!). Otherwise you'll need to use some other concurrency technique to get your result and use it. It depends on what you're actually doing with the result of your call function

How to wait for async APIs in Android?

In android, there are many async APIs such as WebView's evaluateJavascript, which will Asynchronously evaluates JavaScript in the context of the currently displayed page. Usually an execution will just proceed to the successive statements after the call of an async API without any waiting.
But how can I wait until this call finishes its executing, before proceeding to the successive statements. For example,
webview.evaluateJavascript("JS code", new ValueCallback<String> {
public void onReceiveValue(String value) {
//get JS return here
}
});
//Remaining code
How can I make sure the remaining code is executed after webview.evaluateJavascript has finished its executing (i.e., its callback onReceiveValue has finished its executing).
Edit: To be more precise, what I want is that remaining code should be executed after onReceiveValue has finished executing.
I find out a workaround by using JavaScript interface. The idea is that we create a bridge class that contains a method that takes the javascript execution result as input. Then we can obtain the result at the Java end. This method works because bridge methods are invoked by JavaScript code, which is run on another thread. We only need to wait on the UI thread for a little milliseconds, then the result is here for you. The following code is an illustration:
class Bridge {
public String result = null;
#JavascriptInterface
public void putJsResult(String result) {
this.result = result;
}
public String getJsResult() {
return this.result;
}
}
Bridge bridge = new Bridge();
wv.addJavascriptInterface(bridge, "bridge");
webview.evaluateJavascript("bridge.putJsResult(func())", null);
Thread.sleep(100);
//Result is there
String result = bridge.getJsResult();
When you have to wait for code execution, a simple class to use is CountDownLatch.
An example for your problem can be:
public class AboutActivity extends Activity {
private volatile CountDownLatch jsLatch = new CountDownLatch(1);
private volatile String jsReceivedValue = null
initWebView() {
// webview init
...
webview.evaluateJavascript("JS code", new ValueCallback<String> {
public void onReceiveValue(String value) {
//get JS return here
jsReceivedValue = value
jsLatch.countDown();
}
});
try {
// wait 60 seconds or assume there was some problem during the loading
jsLatch.await(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// thread interrupted or time elapsed
}
if (jsReceivedValue == null) {
// show "problem during loading"
} else {
//Remaining code
}
}
}
Note that waiting for code execution on main thread, can lead to unresponsive app.
You can show a loading spinner while using a simple thread to avoid this:
new Thread(new Runnable() {
#Override
public void run() {
initWebView();
}
}).start();

Picasso threads keep running

How I am supposed to shut down picasso properly?
Example:
I only have 1 activity, and in this activity in onDestroy, I call shutdown() on all picasso instances(I don't use the singleton one).
But, until this activity gets destroyed, Picasso is keeping the device awake(I start the app, use it, press home, leave the phone for the weekend alone, check it on monday, the battery is dead because Picasso kept the phone awake).
These Picasso threads are still running:
-Picasso-Stats
-Picasso-refQue (twice)
-Picasso-Dispatcher (twice)
Why? Are they supposed to?
What's the best practice for shutting it down? In onStop()? And I should keep a list of unfinished downloads that I might want to retry in onResume()?
As far as i know default singleton instance in picasso cannot be shutdown,
but i solved problem, in 'picasso.java' file at line : 643
found this code:
#Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
// Prior to Android 5.0, even when there is no local variable, the result from
// remove() & obtainMessage() is kept as a stack local variable.
// We're forcing this reference to be cleared and replaced by looping every second
// when there is nothing to do.
// This behavior has been tested and reproduced with heap dumps.
RequestWeakReference<?> remove =
(RequestWeakReference<?>) referenceQueue.remove(THREAD_LEAK_CLEANING_MS);
Message message = handler.obtainMessage();
if (remove != null) {
message.what = REQUEST_GCED;
message.obj = remove.action;
handler.sendMessage(message);
} else {
message.recycle();
}
} catch (InterruptedException e) {
break;
} catch (final Exception e) {
handler.post(new Runnable() {
#Override public void run() {
throw new RuntimeException(e);
}
});
break;
}
}
}
while (true) have high cpu usage, i decided to change it as follows :
#Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
// Prior to Android 5.0, even when there is no local variable, the result from
// remove() & obtainMessage() is kept as a stack local variable.
// We're forcing this reference to be cleared and replaced by looping every second
// when there is nothing to do.
// This behavior has been tested and reproduced with heap dumps.
RequestWeakReference<?> remove =
(RequestWeakReference<?>) referenceQueue.remove(THREAD_LEAK_CLEANING_MS);
Message message = handler.obtainMessage();
if (remove != null) {
message.what = REQUEST_GCED;
message.obj = remove.action;
handler.sendMessage(message);
} else {
message.recycle();
}
Thread.sleep(2000);//===> call ever 2 sec to decrease cpu pressure.
} catch (InterruptedException e) {
break;
} catch (final Exception e) {
handler.post(new Runnable() {
#Override public void run() {
throw new RuntimeException(e);
}
});
break;
}
}
}

If I finish an activity and call it again, it's attribute values still remain inside thread (RunOnUiThread)

In this case, I have 2 activities. I'm on Activity 1 and go to Activity 2. The application works as intended.
The problem starts when I go back to Activity 1, and start Activity 2 again.
See code below:
public class ScreenWActivity extends SerialComActivity {
private static final String tag = "ScreenWActivity";
private TextView mReception, m_tvDate, mtvPesoPercent, mtvState;
public String mCommand = null;
public int mActualProcess, mNextProcess;
private Commands mLastCommand;
public SettingsGlobal mSettings;
public int mAttempts = 0;
public long mStartTime, mTimeout;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_W);
this.mSettings = new SettingsGlobal(this); // get global settings
this.mtvState = (TextView) findViewById(R.id.tv_state); // label to update the current state
startSerialConnection(); // open serial port and start connection. inherited from SerialComActivity (the upper class)
this.mTimeout = 10; // timeout for commands response in seconds
this.mNextProcess = 1; // the next step in the process, its updated in the stepN() methods
this.mActualProcess = 1; // current step in the processo
this.mLastCommand = Commands.OPEN_DOOR; // the last command I've sent, to know what to expect in return
this.executeWorkflow(mNextProcess); // starts the workflow
}
private void step1(){
this.mtvState.setText("Closing door."); // update status
this.writeSerial(Commands.OPEN_DOOR.command("080").getBytes()); // sends the command to the outputstream, the external device reads the command, execute it and respond back
this.mNextProcess = 2; // the next step in the process is 2
this.mActualProcess = 1; // just tracking
this.mLastCommand = Commands.OPEN_DOOR;
startCounting(); // starts the timout, I've sent the command, now I wait for an answer
}
private void step2(){
this.mtvState.setText("Testando peso das balanças 1.");
this.writeSerial(Commands.GET_W.command().getBytes()); // get weight from weighing-machine
mLastCommand = Commands.GET_W; // the last command i sent i requested the weight - now I know what to expect
mNextProcess = 3; // next step in the sequence in case everything goes according to plan
this.mActualProcess = 2; // tracking
startCounting(); // starting timeout to get an answer
}
private void step3(){...}
private void step4(){...}
private void step5(){...}
private void step6(){...}
#Override
protected void writeSerial(byte[] buffer){...}
public void startCounting(){
mStartTime = System.currentTimeMillis();
timerHandler.postDelayed(timerRunnable, 0);
}
public void stopCounting(){
timerHandler.removeCallbacks(timerRunnable);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
stopCounting();
timerRunnable = null;
if(this.mSerialPort != null)
this.mSerialPort.close();
this.mSerialPort = null;
if(AppConfig.DEBUG) Log.i(tag, "finishing!");
finish();
super.onDestroy();
}
public void executeWorkflow(int step) {
switch(step){
case 1:
step1();
break;
case 2:
step2();
break;
case 3:
step3();
break;
case 4:
step4();
break;
case 5:
step5();
break;
case 6:
step6();
break;
}
}
protected boolean validateReturn(String resposta) {
/// we check the command we've sent and the response we're given. if it matches, then we return true, else false
}
// overrided from SerialComActivity, called when the external equipment sends a message to us
// ITS CALLED WHEN THERE IS INPUT FROM THE EXTERNAL EQUIPMENT
#Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
public void run() {
stopCounting(); // we remove the callbacks from the timeout thread
if( validateReturn(new String(buffer, 0, size).trim()) ){ // we check if the response is good
executeWorkflow(mNextProcess); // if its good, we move to the next step
}else{
mtvState.setText("invalid return"); // if not we message the user
executeWorkflow(mActualProcess); // we try again
}
}
});
}
// RESPONSIBLE FOR THE TIMEOUT
// the code below was created intending to implement a timeout timer for waiting a response from the external device
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
long millis = System.currentTimeMillis() - mStartTime;
long seconds = (millis / 1000);
timerHandler.postDelayed(this, 500);
if(mTimeout - seconds == 0 ){
mAttempts += 1;
if(mAttempts == 3){ // we make 3 attempts to get a response, if it is the third, we quit trying and give error
mAttempts = 0;
mtvState.setText("Could not communicate.");
stopCounting(); // we end the timer
}else{
executeWorkflow(mActualProcess); // if we can still try, we send the command again
}
}
}
};
}
Inside the method onDataReceived(), which is called everytime I get a response from the external equipment, I use the attribute mLastCommand (which indicates the last command I've sent), so this way I know how to validate the response I get.
When I go back to Activity 2, in the class scope the values of the attributes are the same as the ones I've defined in the onCreate() method. In the LogCat I saw that the attributes values are correctly defined as stated in OnCreate.
BUT, when the method onDataReceived (it's inside a Thread in the SerialComActivity class) is called (which is called when I get data from outside) the value of this same attribute mLastCommand is the same as the first time I started the activity, regardless of the value I define for it. As if the the runnable inside RunOnUiThread is still holding the old values from the first time I entered the activity, and outside of it the class has the values I have defined.
It's like having two different attributes with the same name in the ScreenWActivity.
I tried nulling the attributes inside the onDestroy() method, but to no avail.
Below is the code for the SerialComActivity class:
public abstract class SerialComActivity extends Activity{
SerialPort mSerialPort = null;
protected OutputStream mOutputStream;
protected InputStream mInputStream;
protected ReadThread mReadThread;
private class ReadThread extends Thread {
#Override
public void run() {
super.run();
while(!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) return;
size = mInputStream.read(buffer);
if (size > 0) {
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
protected void startSerialConnection(){
try {
mSerialPort = new SerialPort(new File("/dev/ttyS2"), 38400, 0);
} catch (SecurityException e) {
// TODO Auto-generated catch block
if(AppConfig.DEBUG)
Log.e("SERIAL", "portopen ERR: " + e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
if(AppConfig.DEBUG)
Log.e("SERIAL", "portopen ERR: " + e.getMessage());
}
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread */
mReadThread = new ReadThread();
mReadThread.start();
}
protected abstract void onDataReceived(final byte[] buffer, final int size);
protected abstract void writeSerial(byte[] buffer);
#Override
protected void onDestroy() {
if (mReadThread != null){
mReadThread.interrupt();
if(AppConfig.DEBUG) Log.i("ThreadSerial", "interrupting");
}
if(mSerialPort != null)
mSerialPort.close();
mSerialPort = null;
finish();
super.onDestroy();
}
}
I'm still in the process of learning Java and Android programming, so please forgive me if I'm doing something wrong. I looked up around, and the thing that you can't use variables other than "final" inside the RunOnUiThred came up. But I think it's not the issue, since it works the first time I start the activity.
Try doing your clean up in onPause() instead of onDestroy(), onDestroy() may not be called immediately which means there may be a read conflict on SerialPort. Also if you are already in onDestroy(), calling finish() doesn't really do anything.
Lastly, for a finite resource like SerialPort connection, it's better to put it in a Service.
I'm a newbie in Java, but I think I found out what was happening. The thing is that I asked the wrong question.
The problem is in the mInputStream.read(). As I've come to know, it's a blocking operation. I'm creating a thread that stays blocked in that read() method. After I finish the Activity, (go back to the first one), the thread keeps running. I know that because when a send some information through the serial interface, that thread responds.
So what I did, and it's working for me, altough many people stated that this method is not recommended is use mInputStream.available():
try {
if (mInputStream == null){ Log.i(tag,"returning"); return null ;}
Log.i(tag,"reading");
mEmptyStream = true;
while(mEmptyStream && !mFinish){
Log.i(tag,"input while");
/// checking if there is info, so we don't block the thread
if(mInputStream.available() > 0){
Log.i(tag,"input avail : " + InputStream.available());
//stream not empty
mEmptyStream = false;
size = mInputStream.read(buffer); //
}
}
if (size > 0) {
Log.i(tag,"size > 0 = " + new String(buffer, 0, size));
return new String(buffer,0,size);
}else{
Log.i(tag,"size <= 0");
}
}
Basically I loop using available(). When I finish the activity, in the onPause() method I set the field mFinish to true, this way the thread finds it's way out of execution and can end properly. It's the way I found and it's working so far. I improved the code significantly after the original post, like not running non UI jobs in the RunOnUiThread :)
But I tested it and it's working.

How to handle variables shared between UI thread and another thread in android?

I am trying to develop an audio processing related app in android. I have one thread(not the UI thread) in which I am doing an operation. I need to update the result of the operation while it is still going on. For the same I am using a Handler. I am just using a Toast to display the result inside the handler. As of now my thread is continuing to run for the first time alone and after displaying the first result the thread doesn't run anymore because of which results are not updated. I just came to know that while modifying variables shared by this Thread and the UI, I need to synchronize both the threads. Am I correct? If so how can I achieve it?
Thanks!!
EDIT
I am posting a part of the method which is running in my thread and my handler.
while(fulldatabuffcnt+200<=fulldatabuffer.size())
{
double[] windowdata=new double[200];
classlabel=0;
//classlabel_new=0;
int windowcnt=0;
for (int h=fulldatabuffcnt;h<fulldatabuffcnt+200;h++)
{
windowdata[windowcnt]=fulldatabuffer.get(h);
windowcnt++;
}
MFCCcoeffs=mfcc_inst.getParameters(windowdata);
classlabel=likeli_ref.llhmain(MFCCcoeffs);
try {
out.writeInt(fulldatabuffer.size());
} catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
classlabel_array[ecount]=classlabel;
ecount++;
if (ecount==25)
{
synchronized(SharedData.globalInstance) {
SharedData.globalInstance.classlabel_new =occurence(classlabel_array);//<--shared variable classlabel_new getting modified
}
try {
out_max.writeInt(SharedData.globalInstance.classlabel_new);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
ecount=0;
uiCallback.sendEmptyMessage(0);
}
fulldatabuffcnt=fulldatabuffcnt+80;
}
if(fulldatabuffcnt+200>fulldatabuffer.size()){
AppLog.logString("Setting calclating thread to null");
calculatingThread = null;
}
try {
out.close();
out_max.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
private Handler uiCallback = new Handler () {
public void handleMessage (Message msg) {
int label_handler;
synchronized(SharedData.globalInstance) {
label_handler=SharedData.globalInstance.classlabel_new;
}
Toast.makeText(MFCC2Activity.this, "Classified label" +label_handler, Toast.LENGTH_SHORT).show();//<--trying to access classlabel_new
}
};
Yes, you should synchronize to make sure that your UI thread doesn't access variables that are only partially set up by your own thread.
I suggest that you have a singleton object what contains all the variables/data etc that you need to pass between the two threads. For example, suppose you need to share a string and a double between your own thread and the UI thread. Create a class SharedData with a singleton, e.g.
class SharedData {
public String aString;
public double aDouble;
public static SharedData globalInstance = new SharedData();
}
Then in your own thread where you want to set the data
synchronized(SharedData.globalInstance) {
SharedData.globalInstance.aString = "some string";
SharedData.aDouble = 42.0;
}
and in your UI thread
String aString;
double aDouble;
synchronized(SharedData.globalInstance) {
aString = SharedData.globalInstance.aString;
aDouuble = SharedData.aDouble;
}
// do something with aString and aDouble
If you do it like that, then there won't be any problems relating to partially set data being read by the UI thread.

Categories

Resources