I can call Snackbar.make() from a background thread without any problems. This is surprising to me since I thought UI operations are only allowed from the UI thread. But that is definitely not the case here.
What exactly makes Snackbar.make() different? Why doesn't this cause exceptions like any other UI component when you modify it from a background thread?
First of all: make() doesn't perform any UI related operations, it just creates a new Snackbar instance. It is the call to show() which actually adds the Snackbar to the view hierarchy and performs other dangerous UI related tasks. However you can do that safely from any thread because it is implemented to schedule any show or hide operation on the UI thread regardless of which thread called show().
For a more detailed answer let's take a closer look at the behaviour in the source code of the Snackbar:
Let's start where it all begins, with your call to show():
public void show() {
SnackbarManager.getInstance().show(mDuration, mManagerCallback);
}
As you can see the call to show() gets an instance of the SnackbarManager and then passes the duration and a callback to it. The SnackbarManager is a singleton. Its the class which takes care of displaying, scheduling and managing a Snackbar. Now lets continue with the implementation of show() on the SnackbarManager:
public void show(int duration, Callback callback) {
synchronized (mLock) {
if (isCurrentSnackbarLocked(callback)) {
// Means that the callback is already in the queue. We'll just update the duration
mCurrentSnackbar.duration = duration;
// If this is the Snackbar currently being shown, call re-schedule it's
// timeout
mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
scheduleTimeoutLocked(mCurrentSnackbar);
return;
} else if (isNextSnackbarLocked(callback)) {
// We'll just update the duration
mNextSnackbar.duration = duration;
} else {
// Else, we need to create a new record and queue it
mNextSnackbar = new SnackbarRecord(duration, callback);
}
if (mCurrentSnackbar != null && cancelSnackbarLocked(mCurrentSnackbar,
Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE)) {
// If we currently have a Snackbar, try and cancel it and wait in line
return;
} else {
// Clear out the current snackbar
mCurrentSnackbar = null;
// Otherwise, just show it now
showNextSnackbarLocked();
}
}
}
Now this method call is a little more complicated. I am not going to explain in detail what's going on here, but in general the synchronized block around this ensures thread safety of calls to show().
Inside the synchronized block the manager takes care of dismissing currently shown Snackbars updating durations or rescheduling if you show() the same one twice and of course creating new Snackbars. For each Snackbar a SnackbarRecord is created which contains the two parameters originally passed to the SnackbarManager, the duration and the callback:
mNextSnackbar = new SnackbarRecord(duration, callback);
In the above method call this happens in the middle, in the else statement of the first if.
However the only really important part - at least for this answer - is right down at the bottom, the call to showNextSnackbarLocked(). This where the magic happens and the next Snackbar is queued - at least sort of.
This is the source code of showNextSnackbarLocked():
private void showNextSnackbarLocked() {
if (mNextSnackbar != null) {
mCurrentSnackbar = mNextSnackbar;
mNextSnackbar = null;
final Callback callback = mCurrentSnackbar.callback.get();
if (callback != null) {
callback.show();
} else {
// The callback doesn't exist any more, clear out the Snackbar
mCurrentSnackbar = null;
}
}
}
As you can see first we check if a Snackbar is queued by checking if mNextSnackbar is not null. If it isn't we set the SnackbarRecord as the current Snackbar and retrieve the callback from the record. Now something kind of round about happens, after a trivial null check to see if the callback is valid we call show() on the callback, which is implemented in the Snackbar class - not in the SnackbarManager - to actually show the Snackbar on the screen.
At first this might seem weird, however it makes a lot of sense. The SnackbarManager is just responsible for tracking the state of Snackbars and coordinating them, it doesn't care how a Snackbar looks, how it is displayed or what it even is, it just calls the show() method on the right callback at the right moment to tell the Snackbar to show itself.
Let's rewind for a moment, up until now we never left the background thread. The synchronized block in the show() method of the SnackbarManager ensured that no other Thread can interfere with everything we did, but what schedules the show and dismiss events on the main Thread is still missing. That however is going to change right now when we look at the implementation of the callback in the Snackbar class:
private final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
#Override
public void show() {
sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, Snackbar.this));
}
#Override
public void dismiss(int event) {
sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, event, 0, Snackbar.this));
}
};
So in the callback a message is send to a static handler, either MSG_SHOW to show the Snackbar or MSG_DISMISS to hide it again. The Snackbar itself is attached to the message as payload. Now we are almost done as soon as we look at the declaration of that static handler:
private static final Handler sHandler;
private static final int MSG_SHOW = 0;
private static final int MSG_DISMISS = 1;
static {
sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message message) {
switch (message.what) {
case MSG_SHOW:
((Snackbar) message.obj).showView();
return true;
case MSG_DISMISS:
((Snackbar) message.obj).hideView(message.arg1);
return true;
}
return false;
}
});
}
So this handler runs on the UI thread since it is created using the UI looper (as indicated by Looper.getMainLooper()). The payload of the message - the Snackbar - is casted and then depending on the type of the message either showView() or hideView() is called on the Snackbar. Both of these methods are now executed on the UI thread!
The implementation of both of these is kind of complicated, so I won't go into detail of what exactly happens in each of them. However it should be obvious that these methods take care of adding the View to the view hierarchy, animating it when it appears and disappears, dealing with CoordinatorLayout.Behaviours and other stuff regarding the UI.
If you have any other questions feel free to ask.
Scrolling through my answer I realize that this turned out way longer than it was supposed to be, however when I see source code like this I can't help myself! I hope you appreciate a long in depth answer, or maybe I might have just wasted a few minutes of my time!
Snackbar.make is completely safe from being called form non-ui thread. It uses an handler inside its manager which operates on the main looper thread and thus hides the caller form the underlying complexities of it.
Only the original thread that created a view hierarchy can touch its views.
If you use the onPostExecute you'll be able to access the views
protected void onPostExecute(Object object) { .. }
Related
i am newbie on android development and i would like to ask how to wait some async tasks that already running. Also when i am trying to sleep the main Thread many of them are suspended by the system. When i use an arraylist to add them and then call to each of them get() many of them never finish on time. Please give me a code example because i searching it over of three days...
Thx!!
for(){
async...
async.execute();
arraylist.add(async);
}
...
for(arraylist.size){
arraylist.get().get();
}
I will try to answer your question here but the question is not clear.
If you want to check whether there is an AsyncTask completed or not in an arraylist, we can use getStatus call that return us a status, and one of the status, luckily, is FINISHED, so you can check your status of any given AsyncTask.
If you want to sleep until one of the AsyncTask is finished, then the best approach probably involves doing something in onPostExecute. When you override it, you can do something to notify the main thread. One of the ways you can do this is here:
public interface Callback {
public void callBack(int id);
}
public class MainActivity implements Callback {
private void function() {
//do your thing
AsyncTask task0 = new MyAsyncTask(this, 0); //implement your own asynctask here,
//with one of the parameters this activity so that you can get a callback.
//Also, optionally give in the id so that you know what index of asynctask is finished first.
//do the same thing for other tasks
task1.execute(params);
}
public void callBack(int id) {
arrayList.get(id).get(); //this is done
}
In your AsyncTask, you simply override the onPostExecute to something like this
protected void onPostExecute (Result result) {
//do your thing
mainActivity.callBack(id);
}
Hope this helps.
I have an interface method which is supposed to return a Future object.
Future<Result> doSomething()
The implementation of this method shows some ui (javafx).
One of the ui elements has a listener, that needs to be called in order to receive the actual result, I need.
How do I achieve this?
Is there a better solution?
Here an example action I need to wait for:
// this is some framework method I cannot change
#Override
public Data execute(Data data) {
Future<Data> dataFuture = handler.doSomething(data);
// this should basically wait until the user clicked a button
return dataFuture.get();
}
// handler implementation
public Future<Data> doSomething(Data data) {
// the question is how to implement this part, to be able to
// return a future object
Button button = new Button("Wait until click");
// create thread that waits for the button click ?!????
// modify incoming data object when the button was clicked
// somehow create the Future object that's bound to the button click
return future;
}
This is what I want to achieve:
my method doSomething shows a new scene(ui) with a button on it
and returns immedeately the future object
future.get() waits until the user pressed the button
limitations: it has to be done with no extra library and on >=Java7
Use a javafx.concurrent.Task. It derives from FutureTask. There are extensive examples in the linked javadoc on Task usage.
Oracle also provide a tutorial which discusses Task usage:
Concurrency in JavaFX
I think this is what you want, but I may have understood the question, if so, please edit the question a bit to clarify requirements (perhaps with an mcve). The bit that makes me a little unsure is the part in your title "waiting for ui event?", I'm not quite sure what that means in this context.
This is a solution I was searching for. It's not very nice, since the Thread.sleep doesn't convince me.
but now you propably get an idea of what I want to achieve
// make sure this is not called on the ui thread
public Future<Data> doSomething(Data data) {
WaitingFuture future = new WaitingFuture(data);
Platform.runLater(() -> {
Button button = new Button("Wait until click");
button.setOnAction(future);
// show button on ui...
});
favouriteExecutorService.submit(future);
return future;
}
static class WaitingFuture extends Task<Data> implements EventHandler<ActionEvent> {
private Data data;
WaitingFuture(Data originalData) {
this.data = originalData;
}
private Data waitingData;
#Override
public void handle(ActionEvent event) {
waitingData = data.modify();
}
#Override
protected Data call() throws Exception {
while (waitingData == null) {
Thread.sleep(100);
}
return waitingData;
}
}
I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}
I've created a Handler that can be accessed from anywhere within the activity and also written a method to make it easier to call the handler:
private Handler textFromBGThread = new Handler() {
#Override
public void handleMessage (Message msg) {
// Get the string from the msg
String outputString = msg.getData().getString("Output");
// Find the TextView
TextView Output = (TextView)findViewById(R.id.ConsoleOutputView);
// Display the output
Log.i("TextOutput","About to display message: " + outputString);
Output.setText(Output.getText() + outputString);
Log.i("TextOutput","Message displayed");
}
};
private void TextOutputWrapper (String outputText) {
Message msg = new Message();
Bundle bndle = new Bundle();
bndle.putString("Output", "\n" + outputText);
msg.setData(bndle);
textFromBGThread.handleMessage(msg);
}
So then this can be called from a background thread simply with:
TextOutputWrapper("Attemping to connect...");
This will work 1+ times, however, the actual visual change will cause a CalledFromWrongThreadException to be thrown. Being new to Java & Android, I'm stuck on why this is happening.
I have noticed that the crash tends to happen when there's a slightly longer time period between calls & that if the calls to TextOutputWrapper(String) are happening very quickly after one another, then it works. For example, this:
int i = 0;
while (i < 200) {
TextOutputWrapper(String.valueOf(i));
i++;
}
works fine.
Having looked at LogCat, it seems that the garbage collector frees up some resources and then the next time TextOutputWrapper(String) is called, it crashes (when Output.SetText(String) is called, to be precise), although I'm not exactly sure why that would cause this error.
There's a few things I'd change here:
Using Handler
A Handler is useful if you want to trigger the UI to update, and do so from a non-UI thread (aka "background" thread).
In your case, it's not serving that purpose. You are directly calling
textFromBGThread.handleMessage(msg);
It's not designed for you to do that. The way you are supposed to use Handler is to implement what you want done to the UI in the handleMessage(Message) method. You did that. But, you shouldn't directly call handleMessage(). If you do that, then handleMessage() will be called from whatever thread invokes TextOutputWrapper(). If that's a background thread, then that's wrong.
What you want to do is to call the handler's sendMessage(Message) method (or one of the other available variants). sendMessage() will put your message in a thread-safe queue, that is then processed on the main thread. The main thread will then invoke your handler's handleMessage(), passing it back the queued message, and allowing it to safely change the UI. So, change TextOutputWrapper() to use this:
private void TextOutputWrapper (String outputText) {
Message msg = new Message();
Bundle bndle = new Bundle();
bndle.putString("Output", "\n" + outputText);
msg.setData(bndle);
textFromBGThread.sendMessage(msg);
}
Java Conventions
This code is a bit hard to read, for an experienced Java developer. In Java, typical coding standards reserve upper case names for things like classes, while methods start with lower case letters. So, please rename the method to:
private void textOutputWrapper (String outputText);
or, better yet, since this is in fact a method, and not a wrapper, per se, rename to something like
private void outputText(String text);
Safe Threading Alternatives
Finally, I might recommend that if you simply want a method that allows you to safely modify the UI from any thread, use another technique. I don't find Handler to be that easy to use for beginners.
private void outputText(final String outputString) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// Find the TextView
TextView output = (TextView)findViewById(R.id.ConsoleOutputView);
// Display the output
Log.i("TextOutput","About to display message: " + outputString);
output.setText(Output.getText() + outputString);
Log.i("TextOutput","Message displayed");
}
});
}
runOnUiThread() is a method available in every Activity.
I'll also point you to some general docs on understanding threading in Android:
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
http://android-developers.blogspot.com/2009/05/painless-threading.html
I have a use-case coming from a GUI problem I would like to submit to your sagacity.
Use case
I have a GUI that displays a computation result depending on some parameters the user set in a GUI. For instance, when the user moves a slider, several events are fired, that all trigger a new computation. When the user adjust the slider value from A to B, a dozens of events are fired.
But the computation can take up to several seconds, whereas the slider adjustment can fire an event every few 100 ms.
How to write a proper Thread that would listen to these events, and kind of filter them so that the repaint of the results is lively? Ideally you would like something like
start a new computation as soon as first change event is received;
cancel the first computation if a new event is received, and start a new one with the new parameters;
but ensure that the last event will not be lost, because the last completed computation needs to be the one with last updated parameters.
What I have tried
A friend of mine (A. Cardona) proposed this low level approach of an Updater thread that prevents too many events to trigger a computation. I copy-paste it here (GPL):
He puts this in a class that extends Thread:
public void doUpdate() {
if (isInterrupted())
return;
synchronized (this) {
request++;
notify();
}
}
public void quit() {
interrupt();
synchronized (this) {
notify();
}
}
public void run() {
while (!isInterrupted()) {
try {
final long r;
synchronized (this) {
r = request;
}
// Call refreshable update from this thread
if (r > 0)
refresh(); // Will trigger re-computation
synchronized (this) {
if (r == request) {
request = 0; // reset
wait();
}
// else loop through to update again
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void refresh() {
// Execute computation and paint it
...
}
Every-time an event is sent by the GUI stating that parameters have been changed, we call updater.doUpdate(). This causes the method refresh() to be called much less.
But I have no control on this.
Another way?
I was wondering if there is another way to do that, that would use the jaca.concurrent classes. But I could not sort in the Executors framework what would be the one I should start with.
Does any of you have some experience with a similar use case?
Thanks
If you're using Swing, the SwingWorker provides capabilities for this, and you don't have to deal with the thread pool yourself.
Fire off a SwingWorker for each request. If a new request comes in and the worker is not done, you can cancel() it, and just start a new SwingWorker. Regarding what the other poster said, I don't think publish() and process() are what you are looking for (although they are also very useful), since they are meant for a case where the worker might fire off events faster than the GUI can process it.
ThingyWorker worker;
public void actionPerformed(ActionEvent e) {
if( worker != null ) worker.cancel();
worker = new ThingyWorker();
worker.execute();
}
class ThingyWorker extends SwingWorker<YOURCLASS, Object> {
#Override protected YOURCLASS doInBackground() throws Exception {
return doSomeComputation(); // Should be interruptible
}
#Override protected void done() {
worker = null; // Reset the reference to worker
YOURCLASS data;
try {
data = get();
} catch (Exception e) {
// May be InterruptedException or ExecutionException
e.printStackTrace();
return;
}
// Do something with data
}
}
Both the action and the done() method are executed on the same thread, so they can effectively check the reference to whether there is an existing worker.
Note that effectively this is doing the same thing that allows a GUI to cancel an existing operation, except the cancel is done automatically when a new request is fired.
I would provide a further degree of disconnect between the GUI and the controls by using a queue.
If you use a BlockingQueue between the two processes. Whenever the controls change you can post the new settings to the queue.
Your graphics component can read the queue whenever it likes and act on the arriving events or discard them as necessary.
I would look into SwingWorker.publish() (http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html)
Publish allows the background thread of a SwingWorker object to cause calls to the process() method, but not every publish() call results in a process() call. If multiple process calls are made before process() returns and can be called again, SwingWorker concatenates the parameters used for multiple publish calls into one call to process.
I had a progress dialog which displayed files being processed; the files were processed faster than the UI could keep up with them, and I didn't want the processing to slow down to display the file names; I used this and had process display only the final filename sent to process(); all I wanted in this case was to indicate to the user where the current processing was, they weren't going to read all the filenames anyway. My UI worked very smoothly with this.
Take a look at the implementation of javax.swing.SwingWorker (source code in the Java JDK),
with a focus on the handshaking between two methods: publish and process.
These won't be directly applicable, as-is, to your problem - however they demonstrate how you might queue (publish) updates to a worker thread and then service them in your worker thread (process).
Since you only need the last work request, you don't even need a queue for your situation: keep only the last work request. Sample that "last request" over some small period (1 second), to avoid stopping/restarting many many times every 1 second, and if it's changed THEN stop the work and restart.
The reason you don't want to use publish / process as-is is that process always runs on the Swing Event Dispatch Thread - not at all suitable for long running calculations.
The key here is that you want to be able to cancel an ongoing computation. The computation must frequently check a condition to see if it needs to abort.
volatile Param newParam;
Result compute(Param param)
{
loop
compute a small sub problem
if(newParam!=null) // abort
return null;
return result
}
To handover param from event thread to compute thread
synchronized void put(Param param) // invoked by event thread
newParam = param;
notify();
synchronized Param take()
while(newParam==null)
wait();
Param param = newParam;
newParam=null;
return param;
And the compute thread does
public void run()
while(true)
Param param = take();
Result result = compute(param);
if(result!=null)
paint result in event thread