Asynchronous Pubnub calls block android ui thread - android

I am trying to get the server time from pubnub with the time method
mPubnub.time(callback);
I suppose it is an asynchronous call then I have a waiting loop just after so I can wait for the result
time = -1;
mPubnub.time(callback);
while(time == -1);
In the call back I have
Callback callback = new Callback() {
public void successCallback(String channel, Object response) {
try {
JSONArray jsonArray = new JSONArray(response.toString());
time = jsonArray.getLong(0) / 10000;
return;
} catch (JSONException e) {
e.printStackTrace();
}
time = 0;
}
public void errorCallback(String channel, PubnubError error) {
Log.wtf("error/" + channel, error.toString());
time = 0;
}
};
All these calls are from doInBackground of an AsyncTask. Why is it blocking my ui thread. Also calls to publish are also blocking my UI thread and I only call them from an AsyncTask
Many people say the while loop blocks the UI thread but I don't understand why that loop in an AsyncTask would block the UI thread. It wasn't in the onPostExecute or onProgressExecute. It was in doInBackground and it shouldn't block the UI.
On the other hand removing the loop still blocks the UI thread
mPubnub.time(callback);
mPubnub.publish(channel, message, true, callback);
these simple calls block the UI thread and the application stops responding.

This is blocking your UI thread:
while(time == -1);
Instead of doing that, you should handle the success/failure via the callback. If the pubnub API takes a callback like this, it would appear as though it is already handling doing it on a background thread. Just take the appropriate action inside the callback handlers.

while(time == -1);
This line blocks your UI Thread, because of this pointer will never updated by other thread, it's not a volatile variable.
You can use Debug Bottle to detect UI Block codes in your project.

Related

How to pause and resume a Thread?

I have a thread:
class SomeRunnable implements Runnable {
#Override
public void run() {
while (true) {
//some code...
try {
Thread.sleep(33);
} catch (InterruptedException e) {
return;
}
}
}
}
which I start using:
someThread = new Thread(new SomeRunnable());
someThread.setName("SomeThread");
someThread.start();
If I want to stop the thread I simply interrupt it:
someThreat.interrupt();
How can I later resume the thread?
Thank you!
You can use wait() and notify() method.
wait()
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
notify()
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

Thread.sleep() vs handler.postDelay() to execute network call in every 30sec

I want perform a network call in every 30sec to push some metrics to Server. Currently I am doing it using thread.sleep(). I found some articles saying thread.sleep() has some drawbacks. I need to know am I doing it right? or Replacing the thread with Handler will improve my code?
public static void startSending(final Context con) {
if (running) return;
running = true;
threadToSendUXMetrics = new Thread(new Runnable() {
#Override
public void run() {
do {
try {
Thread.sleep(AugmedixConstants.glassLogsPushInterval);
} catch (InterruptedException e) {
mLogger.error(interrupt_exception + e.getMessage());
}
// to do to send each time, should have some sleep code
if (AugmedixConstants.WEBAPP_URL.equals(AugmedixConstants.EMPTY_STRING)||!StatsNetworkChecker.checkIsConnected(con)) {
Utility.populateNetworkStat();
mLogger.error(may_be_provider_not_login_yet);
} else
sendUXMetrics();
} while (running);
if (!uxMetricsQueue.isEmpty()) sendUXMetrics();
}
});
threadToSendUXMetrics.start();
}
If You are using only one thread in the network, then usage of the thread.sleep() is fine. If there are multiple threads in synchronization, then the thread.sleep() command will block all the other threads that are currently running.
As per the details you've provided, there is only one thread present which isn't blocking any other active threads which are running in synchronization, so using thread.sleep() shouldn't be a problem.
Use Handler.postDelayed to schedule tasks if you are working in UI Thread and Thread.sleep if you are working in background thread.
Apparently you are sending some data using network, you must do it in the background thread, hence Thread.sleep is recommended.
Simple is:
Thread.sleep(millisSeconds): With this method, you only can call in background tasks, for example in AsyncTask::doInBackground(), you can call to delay actions after that. RECOMMENDED CALL THIS METHOD IN BACKGROUND THREAD.
Handler().postDelayed({METHOD}, millisSeconds): With this instance, METHOD will trigged after millisSeconds declared.
But, to easy handle life cycle of Handler(), you need to declare a Handler() instance, with a Runnable instance. For example, when your Activity has paused or you just no need call that method again, you can remove callback from Handler(). Below is example:
public class MainActivity extends Activity {
private Handler mHandler = Handler();
public void onStart(...) {
super.onStart(...)
this.mHandler.postDelayed(this.foo, 1000)
}
public void onPaused(...) {
this.mHandler.removeCallback(this.foo)
super.onPaused(...)
}
private Runnable foo = new Runnable() {
#Override
public void run() {
// your code will call after 1 second when activity start
// end remove callback when activity paused
// continue call...
mHandler.postDelayed(foo, 1000)
}
}
}
The code above just for reference, I type by hand because don't have IDE to write then copy paste.

Why do we use a Handler? Why we don't call an interface element inside a Runnable object?

Whenever this code is executed the application crashes, but when a handler is used the application works as expected.
Runnable r = new Runnable() {
#Override
public void run() {
long futuretime = System.currentTimeMillis()+10000;
while(System.currentTimeMillis()<futuretime){
synchronized (this){
try {
wait(futuretime - System.currentTimeMillis());
} catch (Exception e) {}
}
}
//this code needs to be inside a Handler ??
TextView time = (TextView)findViewById(R.id.timedisplay);
time.setText("Changed Man!!");
//this code needs to be inside a Handler ??
}
};
Thread thread = new Thread(r);
thread.start();
}
Here all the answer have mentioned use of handler is used in Android with UI thread. But Let me add more to it.
If you have gone Android documentation/tutorial you would know that
When an application component starts and the application does not have
any other components running, the Android system starts a new Linux
process for the application with a single thread of execution. By
default, all components of the same application run in the same
process and thread (called the "main" thread or uiThread).
for more info refer
Now coming to your mentioned example; you have created another thread using Runnable...so there might be scenario you need thread(s) other then just mainThread in Android Application.
If you are good in JAVA Threading concept then you would know how Interthread communication happens and for different ways how it can be done refer
So coming back to question in android we have mainThread or uiThread so called which holds our ui i.e. view component. These component are private to mainThread so other thread cannot access it...which has been mentioned in previous answer. This is where Handler comes into picture you do not need to worry how your message would be passed from one thread to another.
Handler
There are two main uses for a Handler: (1) to schedule messages and
runnables to be executed as some point in the future; and (2) to
enqueue an action to be performed on a different thread than your
own.When posting or sending to a Handler, you can either allow the
item to be processed as soon as the message queue is ready to do so,
or specify a delay before it gets processed or absolute time for it to
be processed. The latter two allow you to implement timeouts, ticks,
and other timing-based behavior.
For more info refer docs AND
For more info with handler and UI thread
Code that deals with the UI should be run on the UI (main) thread.
You (probably) create a handler on the UI thread, so all messages sent via it will run on that thread too.
The Runnable is use for background process(background thread) and textview is in your UI thread so background thread can't communicate with foreground thread so it will gives you error and crashes your application.you can also use the runOnUiThread. example.
Runnable r = new Runnable() {
#Override
public void run() {
long futuretime = System.currentTimeMillis()+10000;
while(System.currentTimeMillis()<futuretime){
synchronized (this){
try {
wait(futuretime - System.currentTimeMillis());
} catch (Exception e) {}
}
}
try {
// code runs in a thread
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView time = (TextView)findViewById(R.id.timedisplay);
time.setText("Changed Man!!");
}
});
} catch (final Exception ex) {
Log.i("---","Exception in thread");
}
}
};
Thread thread = new Thread(r);
thread.start();
The reason why your app crashes is that you modify View from a non-UI thread.
If you do it using a Handler that belongs to UI-thread this works as expected.Update
If you need to run Runnable to modify UI you may choose from:
1) yourActivity.runOnUiThread(Runnable r)
2) yourHandlerOnUIThread.post(Runnable r)
3) yourView.post(Runnable r)

Android: Forcing the main run loop to run before current thread of execution is complete

On iOS, if I want my current thread of execution to wait (ie. block) and the main loop to run so that the thread of execution next in the main queue can execute, I invoke:
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
How would I go about doing the equivalent on Android?
This is indeed possible to do in Android. Shachar's answer is on the right track. The problem is not that the main loop will block (unless the code was executed on the main thread, but that's not what the question is proposing). The problem is that the other thread doesn't block, but is simply looping and burning CPU cycles in the while loop. Here is a blocking run on main method I use in my app:
/**
* Runs the runnable on the main UI thread. If called from a thread other than the UI thread,
* this method will block the calling thread and return only after the runnable has completed
* execution on the main UI thread.
* #param runnable Runnable to run on the main UI thread
*/
public static void blockingRunOnMain(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) { // Already on UI thread run immediately
runnable.run();
}
else { // Queue to run on UI thread
final MainRunMonitor lock = new MainRunMonitor();
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(runnable);
// Task to notify calling thread when runnable complete
mainHandler.post(new Runnable() {
#Override
public void run() {
synchronized (lock) {
lock.mRunComplete = true;
lock.notify();
}
}
});
// Block calling thread until runnable completed on UI thread
boolean interrupted = false;
try {
synchronized (lock) {
while (!lock.mRunComplete) {
try {
lock.wait();
} catch (InterruptedException e) {
// Received interrupt signal, but still haven't been notified, continue waiting
interrupted = true;
}
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt(); // Restore interrupt to be used higher on call stack (we're not using it to interrupt this task)
}
}
}
}
MainRunMonitor is a simple class, in my case a private inner class to the class that implements blockingRunOnMain():
/**
* Monitor to lock calling thread while code is executed on UI thread.
*/
private static class MainRunMonitor {
private boolean mRunComplete = false;
}
blockingRunOnMain() is used by passing it a Runnable to run on the main thread:
blockingRunOnMain(new Runnable() {
#Override
public void run() {
workToDoSynchronouslyOnMain();
}
});
The first part of the blockingRunOnMain() method checks if the method is being called from the main thread and if so, simply executes the code immediately. Since the function of blockingRunOnMain() is to synchronously run the Runnable code before the method returns, this will have this same result even if called from the main thread itself.
If the method is called from a thread other than the main thread, we then post the Runnable to a Handler which is bound to the main thread's Looper. After posting the Runnable parameter, we then post another Runnable that will execute after the Runnable parameter completes execution, since the Handler executes posted Messages and Runnables in order. This second Runnable serves to notify the blocked thread that the work has been completed on the main thread.
After posting the second Runnable we now block the background thread and wait until we're notified. It's important to synchronize the operations performed on lock so that the operations are atomic on each thread.
The background thread calls wait() on the monitor and waits until mRunComplete == true. If it gets an InterruptedException, it's important to continue waiting and restore the interrupted state of the thread after we're done, since we're not using the interrupt mechanism ourselves to cancel our task, restoring it allows another method higher on the call stack to handle the interrupt. See "Dealing with InterruptedException".
When the Runnable parameter has completed execution and the second posted Runnable executes, it simply sets mRunComplete to true and notifies the blocked thread to continue execution, which finding mRunComplete == true now returns from blockingRunOnMain(), having executed the Runnable parameter synchronously on the main UI thread.
One short workaround is to have a boolean that is changed by the next main thread loop.
running on main thread can be done with runOnUIthread (or getting the main looper yourself)
moving to the next loop can b easely done with handler.postDelayed(Runnable run, long delayMills), and a no-time delay.
so you could do this:
nextMainLoopDone = false;//This should be changed to a thread safe boolean, could use AtomicBoolean
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
nextMainLoopDone = true;
}
}, 1/* delay for no time, just to next loop*/);
while(!nextMainLoopDone) {
;
}
I'm sorry to disappoint you, but it is not possible to do what you're asking for in Android.

Android: Pause the thread for several seconds

ExecutorService exec = Executors.newFixedThreadPool(8);
List<Future<Object>> results = new ArrayList<Future<Object>>();
// submit tasks
for(int i = 0; i < 8; i++) {
results.add(exec.submit(new ThreadTask()));
}
...
// stop the pool from accepting new tasks
exec.shutdown();
// wait for results
for(Future<Object> result: results) {
Object obj = result.get();
}
class ThreadTask implements Callable<Object> {
public Object call() {
// execute download
//Inside this method I need to pause the thread for several seconds
...
return result;
}
}
As shown above in the comment I need to pause the thread for several seconds. Hope you can help me with this.
Thanks for your time!
Just call Thread.sleep(timeInMillis) - that will pause the current thread.
So:
Thread.sleep(5000); // Sleep for 5 seconds
Obviously you shouldn't do this from a UI thread, or your whole UI will freeze...
Note that this simple approach won't allow the thread to be woken up other by interrupting it. If you want to be able to wake it up early, you could use Object.wait() on a monitor which is accessible to whichever code needs to wake it up; that code could use Object.notify() to wake the waiting thread up. (Alternatively, use a higher-level abstraction such as Condition or Semaphore.)
you could implement a new thread, which is not the UI thread..
something like this might do it for you..
class ThreadTask implements Callable<Object> {
public Object call() {
Thread createdToWait= new Thread() {
public void run() {
//---some code
sleep(1000);//call this function to pause the execution of this thread
//---code to be executed after the pause
}
};
createdToWait.start();
return result;
}

Categories

Resources