I have two JNI native methods that callback Java methods in my UI.
1) Display progress..
2) Dismiss progress
Both of the above calls are definitely in sequence. They both call Java methods that create new runnables as follows:
m_Activity.runOnUiThread( new Runnable()
{
#Override
public void run()
{
DisplayProgressUpdate( m_ProgressPercent );
}
} );
--
m_Activity.runOnUiThread( new Runnable()
{
#Override
public void run()
{
m_Progress.dismiss();
}
} );
What I am seeing is that the dismiss runnable is happening before the progress update runnable completes. I would have thought that because they were called in sequence and because they are both being requested on the same (UI) thread that they would occur in sequence as well. Is this not the case?
Is this why I should be using something such as a Handler to synchronise/sequence these calls?
EDIT: OK, I implemented a Handler and still observed the same behaviour. It was actually my debug that confused me. It looked as though the Dismiss Java code was happening before the progress update had completed, but what it was in fact was the Java debug printing as soon as JNI called the Java method which did the posting to the handler - not the actual runnable thread itself. So.. tajonn07 was right in a way - the dialog box was closing before I had a chance to see it and my debug lead me astray. Thanks for helping guys.
I suspect that what you're seeing isn't the dismiss being executed first, but instead it's being executed so quickly after the display that it doesn't even show.
I would suggest using a handler. But even with a handler, if it's in your UI thread, it will freeze your screen.
It's a bit messy, but you could drop both those blocks of code inside another thread with a handler. It's not the cleanest solution but it should do the trick!
runOnUiThread is not added on queue in android , this is called immediately when it invoke.
If you want queue / sequence(ie one after another), you have to use Handler.
Related
I have a method invoked by onClickListener
#Override
public Object getData() {
Thread t = new Thread(new testThread());
t.start();
return false;
}
it start the new Thread well, but when I am trying to do both:
private class testThread implements Runnable{
#Override
public void run() {
OuterClass.this.myActivity.runOnUiThread(new Runnable(){ ... });
OuterClass.this.myActivity.uiHandler.post(new Runnable(){ ... });
...
nothing happens. UI hang up and no Runnable never run (I see it during careful debugging).
Why? Everything should work or even if it fail, why the UI hangs??
Please help!
SOLVED!!! The problem was in method which invokes getData (outside the scope), it never finished failing into infinite loop. Since that scheduled Runnables never started as I think. Now everything works .
AsyncTask is better. It is easier to use, you don't have to manually manage so many threads, and it keeps your code clean.
The doInBackground() method will do your lengthy task on an alternate thread. If you want to update your UI when the task is running, use the publishProgress() method, and if you want to update the UI after the work is done, use onPostExecute().
As to your question on why the UI hangs, see if you are using any method that takes very long or blocks for some reason in the runOnUiThread() method. If any code takes time, remove it from this method.
Quick question: I have been using frameworks that spawn worker threads to perform asynchronous tasks, a good example is Retrofit. Within the success/failure sections, I may pop up a Dialog box which would need to be on the UI thread. I have been accessing the underlying
Activity/UI thread in this fashion within the success/failure sections of Retrofit:
Dialog dialog = new Dialog(LoginActivity.this, R.style.ThemeDialogCustom);
This works well 99.9% of the time but every once in a while, I receive the following error when creating a Dialog box:
android.view.WindowManager$BadTokenException
LoginActivity.java line 343 in LoginActivity$6.success()
Unable to add window -- token android.os.BinderProxy#41662138 is not valid;
is your activity running?
So, is my approach the most stable way to access the Activity context/UI thread from a worker thread or do I need a different approach?
If you work with threads and not using Asynctasks, always run everything that changes UI in runOnUIThread like this
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
//change UI
}
});
The more generic way to do it is this, which is pretty much the same
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//change UI
}
})
See here the minimal difference between runOnUIThread and MainLooper
If you want to check if you are on the main/ui thread
if(Thread.currentThread() == Looper.getMainLooper().getThread()) {
//you are on the main thread
}
AFAIK, there is nothing wrong with the approach you are using. The problem is occurring because the by the time the worker thread finishes and you are trying to show the dialog, the instance of the Activity has finished. So, the crash is totally dependent on the amount of time it takes for the thread to finish. And it seems that in your case, the thread mostly finishes when the Activity is still active; hence you don't get the error is most cases.
What you need to do is to check if the Activity is still running before trying to show the Dialog. One of the simplest ways would be to
if(!((Activity) LoginActivity.this).isFinishing())
{
//safe to show your dialog
}
From my main thread, I start an AsyncTask which will go through a list of images and for each image, it will do some processing on it. So basically, there's a for loop and inside it, another AsyncTask is called. I use an instance of a class which holds the boolean value for checking if each image is done with its processing, its called a dummyStructure.
Code of the main thread:
new BatchProcessor().execute()
the doInBackground of the BatchProcessor:
protected Void doInBackground(Void... params){
while(dummyStructure.isWorking())
{
//Try loop
thread.sleep(1000);
}
dummyStructure.setIsWorking(true); //basically sets the flag to true
for(String s: pictureList)
{
RunTheProcessingLoop().execute();
}
The Problem:
I tried debugging, and here's what the problem is imo, if I remove the line just outside the while loop dummyStrucutre.setIsWorking(true) then there are multiple asyncTasks called even before it finishes, and basically everything gets screwed up. However, if I don't remove that line, then the BatchProcessor AsyncTask gets caught in the while loop, while as the RunTheProcessingLoop AsyncTask never executes beyond its onPreExecute()(debugged to know that, I used Log.e() in every method of that asyncTask).
Definitely I'm missing something, any help? Thanks a lot! :)
What you are encountering is asynctasks getting piled up because you are starting one from another and not exiting the first. This is because the asynctasks are handled serially by a single thread by default. If you want to use multiple threads in parallel, you'd need to use your own thread executor. See the AsyncTask documentation for more details.
So after 2 days of posting this question and finding out more about what people posted, I figured this:
My main thread called for an AsyncTask and I wanted to wait for that AsyncTask to finish. So I used a boolean flag which the AsyncTask sets to false once it is done and I can queue another task. Here's the code:
class mExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}}
Now, all you need to do is, whatever task/method/etc you want to run Asynchronously, simply create a thread and push it in that class, example:
Thread t = new Thread(new Runnable() {
public void run() {
new someshit().execute();
}
});
new mExecutor().execute(t);
and Tada! Now they both won't be queued/synchronized but would run in parallel.
If I am wrong, please correct me! Thanks! :)
Is there any callBack to setContentView in Android, since i'm doing a heavy operation right after setContentView line, and it seems to skip that setContentView.
So i was thinking of moving the heavyOperation to the callBack of setContentView.
Thanks
EDIT:
Pseudo Code:
AudioRecord Finishes
SetContentView(1) //To show a "Processing" screen with no buttons
FFT analysis
SetContentView(2) //On FFT analysis DONE.
In my case "SetContentView(1)" NEVER occurs.
EDIT # 2:
I did the heavy operation in another Thread, and used Handler to send a Message after heavy operation finishes to treat it as a callBack.
Thanks for all the help guys
Short answer: No callback for the setContentView.
If you are doing network operation then you can use the AsyncTask for this.
If you are doing any more heavy operation and want to update the UI then you can do that using the Service and BroadCastReceiver.
For this you have to make your own callback using the interface.
heavy work should be done in asynk tasks or as a service or on other threads
Don't do any heavy calculations on the main UI thread where onCreate() and such are run.
What happens that the first setContentView() posts a "layout and draw" message to the UI thread message queue. Then your calculation blocks the UI thread, preventing messages in the queue from being processed. The second setContentView() posts another message to the queue. When the control eventually returns to the message loop, both messages are processed and you'll get the layout set up by the last call to setContentView().
For heavy computations, use a separate thread. For example, an IntentService or an AsyncTask make threading easier.
My hack.
final Handler handler = new Handler();
setContentView(layoutResID); // This posts some messages to message queue.
handler.post(new Runnable() { // Post another message at the end.
#Override
public void run()
{
// Called after layout has changed.
// If you want to skip some more works (like transitions),
// call another handler.post() here.
}
});
To see what happens, set a break point at the line Message msg = queue.next(); in Looper.loop() may help.
I was facing a quite similar problem a day ago, but I figured it out. (I know your problem is solved, just offering a different approach which doesn't require a handler or callback.
Most Suitable for running U.I. functions :
If you need to do something like this :runTask() then
setContentView() (or any other ui function) you can run the task on different thread by using AsyncTask or you can set a timer for when the task is completed (if your task takes a certain time), the User Interface functions will be called.
But since the Timer class, runs the functions on a different thread, you can not run the setContentView() inside it. So you can use a runOnUiThread(Runnable action) method inside the overloaded run() function of Timer class. You just need to define a function that returns a runnable. Define your Ui operations in the runnable action.
Hope it helps someone.
I am a new Android developer. I am using the Handler class to schedule some operations. So I am creating runnable objects that calls some of my instance methods.
But I have a problem. Sometimes my run() method in Runnable object is called twice.
What could be the problem??
and there is the code
//deneme is a Handler.
deneme.postDelayed(new Runnable() {
#Override
public void run()
{
randomOyna();
//the instance method that I call.
}
}, 1000);
If don't schedule your Handler to run on another Thread than the UI-thread, there might be a hidden delay in the execution because your Runnable will also run on the UI-thread and thus will only be allowed to run when there is "time" for it. With this hidden delay, it might seem like it is run twice but in reality it's just and over-delayed running before a regular delayed Runnable.
Can't see a mistake just by looking the hint you gave us... But you might try plain old java to run threads instead of handler... Good luck...
Look here for more details