Setting text on TextView from background thread anomaly - java

I've just started playing with Android Concurrency/Loopers/Handers, and I have just faced with strange anomaly. The code below doesn't block me from setting text on TextView from different Thread.
TextView tv;
Handler backgroundHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.sample_text);
Runnable run = new Runnable() {
#Override
public void run() {
Looper.prepare();
backgroundHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String text = (String) msg.obj;
tv.setText(Thread.currentThread().getName() + " " + text);
}
};
Looper.loop();
}
};
Thread thread = new Thread(run);
thread.setName("Background thread");
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = backgroundHandler.obtainMessage();
message.obj = "message from UI";
backgroundHandler.sendMessage(message);
}
And guess what happen
But, when I sleep background thread for a while
backgroundHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String text = (String) msg.obj;
tv.setText(Thread.currentThread().getName() + " " + text);
}
};
it does throw exception as I expected
07-03 18:54:40.506 5996-6025/com.stasbar.tests E/AndroidRuntime: FATAL EXCEPTION: Background thread
Process: com.stasbar.tests, PID: 5996
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7275)
Can someone explain me what happened ? Why I was able to set text from different thread ?

From the very first try, your code is wrong because you created Handler on different thread. This leads to looper/handler is run on different thread. Based on your comment, I guess you know this issue and you want to understand why exception doesn't throw on first try but second.
You should beware this: Accessing UI Element on different thread except from UI Thread causes undefined behavior. This means:
Sometime you see it works.
sometime you don't. You will meet exception as you have seen.
That means Accessing UI Element on different thread isn't always 100% reproducible.
Why you should access all UI Elements only on UI Thread? Because processing UI Element (change internal state, draw to screen ...) is a complex process and need to synchronized between related parties. For example, you call TextView#setText(String) on 2 fragments that both visible on screen. Android doesn't do this concurrently but pushing all jobs into an UI message queue and do that sequentially. This is also true not only from your application viewpoint but also from whole Android system perspective. Updating from status bar that called by system, updating from your app that called by your application always push actions to same UI Message queue before processing.
When you access and modify UI elements on different thread, you broke that process. That means maybe two threads might access and modify an element at same state and same time. As the result, you will meet race condition at some time. That when error occurs.
Explaining for your situation is hard because not enough data for analyzing. But there are some few reasons:
At your first try, TextView haven't displayed on screen yet. So different thread was able to make change on TextView. But on your second try, you sleep for 1 second. At this time, all view has rendered and displayed successfully on screen, so exception threw. You can try Thread.sleep(0) and hopefully your code doesn't crash.
This is will happen in some situations but hard to guess why. That by some chance, both your thread and ui thread accesses same lock object, exception threw.
You can read more about thread issue here Android Thread
Explicit references
Many tasks on non-main threads have the end goal
of updating UI objects. However, if one of these threads accesses an
object in the view hierarchy, application instability can result: If a
worker thread changes the properties of that object at the same time
that any other thread is referencing the object, the results are
undefined.
Hope this help you.

Only the UI Thread can make edits to UI items. In other words, you can not make user interface edits from background threads.
So, instead of tv.setText(Thread.currentThread().getName() + " " + text);, use the following code inside your backgroundHandler :-
runOnUiThread(new Runnable() {
public void run() {
tv.setText(Thread.currentThread().getName() + " " + text);
}
});

Related

How to use Runnable.wait() in AsyncTask? Why does the AsyncTask NOT wait...?

I am using AsyncTask to run a background operation. Of course switching to another thread while already working in a background thread does not make a lot of sense in general, except the other thread is the UI thread. This what I would like to to: While the task is running I need to "access" the UI, e.g. to show a dialog to ask the user how to proceed.
run the background task
stop the task at some point to get user feedback
switch to the UI thread to show dialog and ask for input
switch back to background task and continue work
How can this be done? I thought I could use Runnable with myActivity.runOnUiThread(runnable) but this does not work:
private void copyFiles() {
CopyTask copyTask = new CopyTask(this);
copyTask.execute();
}
// CustomAsyncTask is a AsyncTask subclass that takes a reference to the current
// activity as parameter
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
Within doInBackground() (--> in a background thread) the AsyncTask calls activity.runOnUiThread(uiRunnable). Next uiRunnable.wait() is called. Regarding to the docu wait() should do the following:
Causes the calling thread to wait until another thread calls the
notify() or notifyAll() method of this object.
Thus the background thread should wait to continue its work until this.notify() (== uiRunnable.notifiy()) is called on another thread (= the UI thread), shouldn't it?
Well, id does not wait! After calling uiRunnable.wait() the background thread immediately continues by jumping to if (doCopy).... It seems that the background thread and the main thread are executed in parallel (not surprising since this is what thread do...) and thus its a race condition whether doCopy = false on the UI thread or if (doCopy) on the background thread is reached first.
How is this possible? Why doesn't wait() works as described? Or am I getting something wrong?
Thank you very much!
EDIT:
To avoid missunderstandings: Of course I know the lifecycle methodes of AsyncTask but as far as I understand them, they are not what I am looking for (see my reply to the comment blow).
Interrupting the AsyncTask as soon as a UI interaction is necessary, query the UI and start a new AsyncTask would be possible of course. However this would result in code which is very hard to read/understand/maintain.
As I understand the docu of wait() everything should work fine here. Primary question is not how to do UI interaction during the lifecycle of an AsyncTask but why wait()does not work as expected.
The Basics
When you start an AsyncTask first the onPreExecute() method runs on the UI thread. You can override this method to make changes to the UI prior to the doInBackground() method running.
After the doInBackground() method finishes, the onPostExecute() method runs on the UI thread, so you can use this to make changes to the UI from here. If you need to make regular changes to the UI Thread during the doInBackground() method you override the onProgressUpdate() method which runs on the UI Thread, and then call it from within doInBackground(), which will allow you to periodically update the UI.
You could use something like the following;
private class DoStuffTask extends AsyncTask {
#Override
protected void doInBackground(Object... args) {
// Do stuff
onProgressUpdate(x);
// Do more stuff
}
#Override
protected void onProgressUpdate(Object... args) {
// Update your UI here
}
}
Now if this doesn't quite do it and you want the AsyncTask to wait for input during the doInBackground() method it is probably worth considering using multiple AsyncTasks instead. You can then finish each AsyncTask, ask for input, and then start a new AsyncTask to continue working.
Given that AlertDialog instances are asynchronous, this is probably the preferred solution because you can start the next AsyncTask from the AlertDialog itself.
Using wait() in an AsyncTask
If you would prefer to use a single AsyncTask you can use wait from within your AsyncTask to prevent execution continuing until some condition is met. Instead of using a new Runnable we are just using two threads in this instance, the thread running doInBackground() and the main thread, and we are synchronizing on the AsycTask itself.
Example below;
public class TestTask extends AsyncTask{
private boolean notified;
private Promptable p;
public interface Promptable { public abstract void prompt(); }
public TestTask(Promptable p){
this.p = p;
}
#Override
protected Object doInBackground(Object... arg0) {
Log.d("First", "First");
onProgressUpdate(null);
synchronized(this){
while(!notified){
try{
this.wait();
}
catch(InterruptedException e){ }
}
}
Log.d("Second", "Second");
return null;
}
#Override
protected void onProgressUpdate(Object... args){
synchronized(this){
notified = true;
p.prompt();
this.notify();
}
}
}
In the example above, assume that your Activity is parsed into the AsyncTask's constructor, and that it implements an interface we create called Promptable. You'll notice that even though we're calling wait() we are putting it in a while loop. If we didn't do this, and somehow notify() got called before wait() then your thread would lock up indefinitely. Also, you can't depend on the fact that your thread will wait forever, so the while loop ensures that it doesn't continue until notify is called.
I hope this helps.

Applets - init(), EDT and threads

Java is not my mother tongue and I've been fighting with this problem for a little while.
Basically, I am finding a behavioural difference between calling method switchApplets() directly from init(), and calling it from within a new thread spawned by init().
The consequence of calling it from inside the new thread is that the new applet whitescreens -- until/unless the user resizes or minimizes their browser. If called at the end of init(), the new UI renders immediately without any input from the user. But that's not an option because it doesn't wait for the thread to finish its prep work.
Trimmed-down code:
public class PreLoader extends Applet implements AppletStub {
static JProgressBar pBar = null;
static JLabel message;
public void switchApplets() {
try {
Class main_class = Class.forName("MainClass");
Applet main_applet = (Applet)main_class.newInstance();
removeAll();
setSize(0,0);
setLayout(new GridLayout(1,0));
add(main_applet);
main_applet.init();
main_applet.start();
main_applet.setStub(this);
}
catch (Exception e) {
}
}
public void init() {
pBar = new JProgressBar(0, 100);
pBar.setValue(0);
pBar.setStringPainted(true);
message = new JLabel("Beginning work!");
add(message);
add(pBar);
FlowLayout flow = new FlowLayout();
setLayout(flow);
Thread t = new Thread ( new Runnable () {
public void run ()
{
longRunningFunction1();
longRunningFunction2();
message.setText("Work complete! Stand by..");
switchApplets(); //does NOT work as intended from here
return;
}
} );
t.start();
//switchApplets(); //works as intended if called HERE
}
public void longRunningFunction1() {
//perform some tasks, advance progress bar
}
public void longRunningFunction2() {
//perform some tasks, advance progress bar
}
public void start() {
return;
}
public void appletResize(int width, int height) {
return;
}
}
I tried making init() wait for the thread to finish so that I could call switchApplets() from there, but that only blocked the EDT and prevented the UI from updating. Also tried playing with SwingUtilities' invokeLater/invokeAndWait, but even though switchApplets() gets run on the EDT, it seems that it MUST be called directly from init() (or at least the thread init is running on) to have the desired effect.
Why does calling switchApplets() from within a new thread result in a slightly different (and unwanted) UI behaviour?
The consequence of calling it from inside the new thread is that the new applet whitescreens -- until/unless the user resizes or minimizes their browser.
It's likely a deadlock caused by trying to do UI code on the wrong thread.
I tried making init() wait for the thread to finish so that I could call switchApplets() from there, but that only blocked the EDT and prevented the UI from updating.
You're on the right track. You need to call switchApplets() only from the EDT, and only after the work is done on the other thread.
Are you sure you tried using invokeLater() or invokeAndWait() from within the spawned thread after the long running functions were done? It's been a long while since I did applets but I'm not aware of any applet-specific reason why it wouldn't work, and it would work in any other case. I.e.,
public void run()
{
longRunningFunction1();
longRunningFunction2();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
message.setText("Work complete! Stand by..");
switchApplets();
}
});
}
However, the most proper way to do this is with a SwingWorker rather than a manually created thread. SwingWorker (which is not nearly as well-known as it should be) is designed exactly for the goal of performing background tasks on a separate thread while still being able to update the GUI with progress updates and the results. E.g.,
new SwingWorker<Void,Void>() {
#Override
protected Void doInBackground() { // is called on a background thread
longRunningFunction1();
longRunningFunction2();
return null;
}
#Override
protected void done() { // is called on the Swing thread
message.setText("Work complete! Stand by..");
switchApplets();
}
}.execute();
The Void stuff is because SwingWorker is also capable of returning results and sending intermediate progress updates, but this example doesn't use those features.
You indicated that your long running functions are also updating a progress bar. That's another thing that should happen only on the Swing thread. In practice you can often get away without it, but it's dodgy. Your progress updates can use one of the SwingUtilities.invoke methods, or the mechanisms of SwingWorker; either should work. (SwingWorker itself provides two different ways to do it: Call addPropertyChangeListener (Swing thread) and setProgress (background thread), or call publish (background thread) and override process (Swing thread).)
Also, a small suggestion: if it's inconvenient to deal with a checked exception (or impossible to usefully do so), rather than catching and ignoring it, you should at least catch & rethrow it as an unchecked exception:
catch (Exception e) {
throw new RuntimeException(e);
}
That way, the stacktrace and error message of any exception will not be lost.

Waiting for a Runnable to complete before running another Runnable

I have an Android app with a main tab activity, and several activities within the individual tabs. In my main activity's onCreate(), I have a runnable that creates a list, and in the individual activities, I make use of this list.
In the individual activities's onCreate(), I also have Runnables that operate on the list. However, I need these Runnables to only run when the main tab activity's Runnable completes creating the list, otherwise I'd get a null list. I'm trying to find an elegant way of doing this. Right now, in my main activity's Runnable, I'm setting a global boolean variable isDone, and in my individual activity's Runnable, I'm waiting for isDone to be set via a while loop. This works, but probably isn't the best way of doing so.
Any thoughts?
Thanks.
Edit:
I'm trying the following code out, but I'm getting runtime errors:
In my MainActivity's Runnable:
mainRunnable = new Runnable() {
public void run() {
try {
generateList();
synchronized(this) {
listDone = true;
notifyAll();
}
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
}
};
Thread thread = new Thread(null, mainRunnable, "Background");
thread.start();
In my OtherActivity's Runnable:
otherRunnable = new Runnable() {
public void run() {
synchronized(MainActivity.mainRunnable) {
if (!MainActivity.getListDone()) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
}
};
Thread thread = new Thread(null, otherRunnable, "Background");
thread.start();
The mainRunnable seems to run completely, but the otherRunnable seems to cause the app to crash. I get the following error message:
01-10 15:41:25.543: E/WindowManager(7074): Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#40539850 that was originally added here
01-10 15:41:25.543: E/WindowManager(7074): android.view.WindowLeaked: Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#40539850 that was originally added here
You can use the wait and notify methods.
To do this, there needs to be some globally accessible object whose lock isn't used by anything else in the program at this point in time. I'm assuming that the list-creating Runnable itself can play this role.
So you could add something like this to the list-creating Runnable class:
private boolean listsDone = false;
boolean getListsDone() {
return listsDone;
}
And something like this to its run() method, immediately after it's done creating the lists:
synchronized (this) {
listsDone = true;
notifyAll();
}
And something like this to the other Runnables' run() methods, at the point where they need to wait:
synchronized (listCreatingRunnableObject) {
if (!listCreatingRunnableObject.getListsDone()) {
try {
listCreatingRunnableObject.wait();
} catch (InterruptedException e) {
// handle it somehow
}
}
}
Update: To clarify, both synchronized blocks need to be synchronized over the same object, and you have to call wait() and notifyAll() on that object. If the object is the Runnable, then it can be implicit for the first one (as in the above code), but if it's the activity, you need to explicitly use the activity object in both cases.
You can use a Queue like this:
public class RunQueue implemements Runnable
{
private List<Runnable> list = new ArrayList<Runnable>();
public void queue(Runnable task)
{
list.add(task);
}
public void run()
{
while(list.size() > 0)
{
Runnable task = list.get(0);
list.remove(0);
task.run();
}
}
}
This allows you to use one thread rather than multiple threads. And you can maintain all your existing "Runnable" objects while simultaneously cleaning up any code they have for waits and joins.
Set up a CountDownLatch with a value of 1 in the main thread, then have the dependent threads wait on it. When the main thread is done, you Count Down the latch to 0 and the waiters will start right up.
An active wait using a while loop is not a good idea at all. The simplest thing would be for the first Runnable to just fire up the rest of them as its last step. If that can't be made to work for some reason, take a look at posting a message to a Handler.
Is there a reason you are using Runnables and not Threads? If you use Threads, you can use the various thread communication primitives which exist for this exact reason (wait() and join() in particular).
I have created a helper method that contains all the boilerplate code for posting a runnable and waiting until it finishes running.
The logic is similar to what #Taymon describes, but the implementation is more general.
Check it out:
https://gist.github.com/Petrakeas/ce745536d8cbae0f0761
Maybe you can refer to Looper in Android. Simply, a thead keep running task from queue in a while loop.

How to use MultiThreading in Android for an Event Handling Function (SensorListeners)

I have an event handling mechanism in my Android code to dump the sensor values in a file. Right now, I'm doing it in the main UI thread and hence the UI button responsiveness is very sluggish and I would like to speed it up.
How can I use multithreading on event handling functions? I'm trying to do it like this:
Create a global variable writeNow.
When the sensor value changes, set WriteNow = true
Create a thread in the class which looks like this:
Thread thread1 = new Thread()
{
public void run()
{
if(writeNow == true)
{
try
{
fos.write(s.getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
writeNow = false;
}
}
};
Thus, whenever writeNow is true, it will write to a File and then set WriteNow to false. However, I realize this is not the right approach, because the thread will execute once and then stop executing. When I tried a simple example with a while(true) and wait(), I found that the thread is interrupted millions of times.
So how do I enclose this event handling mechanism in a single thread, for speeding up a process?
Thanks!
You can try one of the following approaches:
It looks like you're trying to keep your writer thread running all the time; what you can do is spawn the thread only when you need it. Take a look at the example in the Android documentation for handling expensive operation in the UI thread.
Here is the example from that page:
public class MyActivity extends Activity {
[ . . . ]
// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler();
// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
[ . . . ]
}
protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mResults = doSomethingExpensive();
mHandler.post(mUpdateResults);
}
};
t.start();
}
private void updateResultsInUi() {
// Back in the UI thread -- update our UI elements based on the data in mResults
[ . . . ]
}
}
Since it doesn't look like you're doing anything in the UI thread once you finish writing you don't really need to bother with a Handler. But you might want to use it to display a Toast once the file has been written to.
On the other hand, if you still want to have a thread running, you might have it sleep() and periodically wake up and check the status of writeNow.
Thread thread1 = new Thread()
{
public void run()
{
while(true)
{
if(writeNow == true)
{
try
{
fos.write(s.getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
writeNow = false;
}
try
{
Thread.sleep(100); //sleep for 100 ms
}
catch (InterruptedException e)
{
Log.d('', e.getMessage());
}
}
}
};
Note that this will quickly get complicated and you might lose the bytes you want to write if your thread is sleeping when new data comes in and when it wakes up, even newer data has been received and has overwritten the previous bytes. You'd need some sort of a queue to manage that.
I'm not sure what you were doing with the wait() but that should've also worked and is in fact, the approach for problems involving a consumer and producer. The idea is to have your thread synchronize and wait() on a shared object (like perhaps your queue of bytes); a second thread will call notify() on the shared object when there is data available to write and the writer thread will be woken up. The writer thread should then write and reloop. Take a look at this tutorial.
As for the interruption of your thread, your thread may be interrupted for a number of reasons which is why it is good practice (especially when using wait()) to ensure that the condition you checked before you called wait() is still valid because you could've been woken because of either a call to notify()/notifyAll() or because of an interruption.
Handler handler = null;
handler = new Handler();
//create another class for and make consrtuctor as u want. so that u can use that effectively.
//for example.
popupIndex = new IndexThread(handler,head, target,ltp,price,IndexNifty.this,columsView,call);
popupIndex.setColumnViewexit(columsView);
handler.postDelayed(popupIndex, 300);
//another class
public IntraThread(Handler handler,String script,int target,int ltp,int price,Intraday intraday,TextView columsView,String call){
super();
this.target = target;
this.ltp = ltp;
this.price = price;
this.intraday = intraday;
this.columsView = columsView;
this.script= script;
this.handler= handler;
this.call= call;
}
public void run(){
// write ur code here....
}

Output to jTextArea in realtime

I have some code which takes a few minutes to process, it has to connect to the web for each string in a long array, each string is a url. I want to make it so that everytime it connects, it should refresh the jtextarea so that the user is not staring into a blank page that looks frozen for 20 min. or however long it takes. here is an example of something i tried and didnt work:
try {
ArrayList<String> myLinks = LinkParser.getmyLinksArray(jTextArea1.getText());
for (String s : myLinks) {
jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}
} catch (IOException ex) {
JOptionPane.showMessageDialog(jTextArea1, "Parsing Error", "Parsing Error", JOptionPane.ERROR_MESSAGE);
Logger.getLogger(MYView.class.getName()).log(Level.SEVERE, null, ex);
}
The problem is that you need to perform the computation asynchronously. You should create a background thread that performs the computation, and then use SwingUtilities.invokeLater to update the JTextArea.
final ArrayList<String> myLinks = //...
(new Thread()
{
public void run(){
for (String s : myLinks) {
try{
final String result = LinkChecker.checkFileStatus(s) + "\n";
SwingUtilities.invokeLater(new Runnable(){
public void run(){
jtextArea2.append(result);
}
});
}catch(IOException error){
// handle error
}
}
}
}).start();
Edit
It has been pointed out that JTextArea's append function actually is thread safe (unlike most Swing functions). Therefore, for this particular, case it is not necessary to update it via invokeLater. However, you should still do you processing in a background thread so as to allow the GUI to update, so the code is:
final ArrayList<String> myLinks = //...
(new Thread()
{
public void run(){
for (String s : myLinks) {
try{
jtextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}catch(IOException error){
// handle error
}
}
}
}).start();
However, for pretty much any other operation that modifies a Swing object, you will need to use invokeLater (to ensure the modification occurs in the GUI thread), since almost all the Swing functions aren't thread safe.
You need to investigate threading and its relationship to GUI updates in Swing. Anything that affects or makes use of GUI components in Swing must done on a special thread called the Event Dispatch Thread (EDT).
If your code snippet, if it's freezing the GUI, I imagine that it is being run in the EDT. Performing a long-running action on the EDT will make the GUI unresponsive, because no further updates can be done while your long-running process is using the thread.
There is a helper class called SwingWorker that allows you to offload long-running computations to a background thread, and then make updates to the GUI thread when it is complete. The SwingWorker looks after the context switches between the GUI thread and the background thread. You can also display progress bars to let the user know the state of the long-running process, so they know your application hasn't hung.
swing/awt is a single threaded library, so once a component is shown, just changing it's appearance won't work correctly. You need to change the component on the GUI Thread, not from your thread. To do this wrap any code that updates a component with SwingUtilities.invokeLater... as in
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
jTextArea2.append(LinkChecker.checkFileStatus(s) + "\n");
}
});
also you want to limit what you do on the gui thread to avoid the gui from becoming sluggish, so if checkFileStatus is time consuming, execute it outside the run method and store the result in a final local variable, and just access the variable in the run() code.

Categories

Resources