Android Activity UI Performance (AsyncTask while-loop) - android

How can I make this more efficient, at the moment it hangs the activity, giving the following information in logcat every time the while-loop completes I assume:
I/Choreographer: Skipped 55 frames! The application may be doing too much work on its
main thread.
Basically on a while-loop it reads a string variable, modifies and splits the string into parts which are then multiplied then divided, these final values are picked up by an interface which changes the custom UI element in the activity.
This seems too heavy on the main UI thread, I was under the impression that handler.post alleviates some of this by adding to the message queue however there are skipped frames.
I've tried to convert this code into an AsyncTask however I don't understand how this code can be converted to work in AsyncTask.
EDIT: AsyncTask custom class replacing old Thread while-loop.
(Old code for reference: http://pastebin.com/Dek6uQTE)
I'm still unsure how this fits in with AsyncTask, I have added the heavy code within the doInBackground() method however readBuf.replace and readBuf.split cannot be resolved. I thought to put the end changed in onProgressUpdate() as opposed to onPostExecute() as this would keep the UI elements updated automatically.
private class PostTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
readBuf = ((MyApplication) getApplication()).getReadBuf();
}
#Override
protected Void doInBackground(Void... readBuf) {
while (readBuf.length > 4) {
readBuf.replace("V", "");
String[] parts = readBuf.split(",");
String part1 = parts[0];
String part2 = parts[1];
speed1 = Float.parseFloat(part1);
speed2 = Float.parseFloat(part2);
finalspeed1 = (speed1 * 102) / div1;
finalspeed2 = (speed2 * 602) / div1;
publishProgress();
}
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
speedometer.onSpeedChanged(speedometer.getCurrentSpeed() - speedcur1);
speedometer.onSpeedChanged(speedometer.getCurrentSpeed() + finalspeed1);
speedometer1.onSpeedChanged(speedometer.getCurrentSpeed() - speedcur2);
speedometer1.onSpeedChanged(speedometer1.getCurrentSpeed() + finalspeed2);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}

You're starting a new thread which is actually just posting a new Runnable to the UI thread (handler is created on the UI thread), so it's not being done in the background. Here are a few tips to help with this:
If you are going to use a background thread to do the "work", then don't post a Runnable which is performing work to the handler, just post the result and update your UI accordingly.
Don't call findViewById() in a loop or any time after creation, if possible. Get a reference to the UI element and stash it off. This method is expensive as it does a search through your view hierarchy for the matching ID.
If you are going to use an AsyncTask just move the "work" part of your Runnable to the doInBackground() method and your UI updates into the onPostExecute() method.
Whether using a custom background Thread or AsyncTask, be sure to shutdown/cancel the work when your Activity leaves the run state, otherwise you will encounter problems as these components are not lifecycle aware.
It's not clear where readBuf is actually pulling data from, so this may also need some work. If this is real-time data coming from some other source, then you may need to have the custom Thread loop with a small yield. If using an AsyncTask, you'll have to create a new one each time as they are one-shot operations and not intended to be used as a long running background thread.
This article on AsyncTask has more details about how it works and pitfalls.

Related

Why should we use aysntask or service instead of a new thread

In android why should we use a asyntask and service, instead of using a new thread() and write the necessary background functionality?
I know that we should not run long running operations like downloading a file from server on the mainthread aka UI thread. And should use a asynctask or service.
But why cant we create a new thread() {which is eventually a new thread other than the main thread} and write necessarily long running operation in that thread.
why did google create the AsyncTask and Service without suggesting to use the regular New Thread()???
thanks in advance
edit1:
may be i wasn't clear in my question or not sure, if i am, even now. help me out.
i get it, the whole point starts from
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
why ?
1.how much can the UI thread handle ? how can we determine a breakpoint? how is a ANR point determined? can we track?
2. when a service component handles long running operations why can't a activity component handle?
Remember that if you do use a service, it still runs in your application's main thread by default, so you should still create a new thread within the service if it performs intensive or blocking operations
http://developer.android.com/guide/components/services.html
the above statement is from android documentation.
3.why cant a service start in a new thread straight away, if we are so concerned about main thread? don't get me wrong in question 3, i am trying to understand the advantage of starting the service in main thread. by default.
in the above statement , does it suggest the main thread's ability to start and handle a service's long running operation load? if so does it contradict with question 1.
Well let's look how you'd perform a simple task using a Thread.
The first step is to create a Thread using a Runnable. Something like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
}
};
new Thread(runner).run();
}
The thing is, we need to show the results so it would actually be more like this:
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void workFinished(List<String> results) {
// show the results on the UI
}
It looks good, but there's a problem; the callback method (workFinished) has to update the UI. If we do this from any non-main thread, there will be big problems. We need a thread-safe way to call that method, which is what Handlers are for. Let's also throw in a method for updating our progress, which is very common. The code would now look like this:
private final Handler myHandler = new Handler();
private void fetchResultsAsync() {
Runnable runner = new Runnable() {
#Override
public void run() {
List<String> results = fetchResultsFromWebServer();
workFinished(results);
}
};
new Thread(runner).run();
}
private void showProgress(int result) {
myHandler.post(new Runnable() {
#Override
public void run() {
// update a progress bar here
}
});
}
private void workFinished(final List<String> results) {
myHandler.post(new Runnable() {
#Override
public void run() {
// show the results on the UI
}
});
}
Compare this to the implementation using an AsyncTask:
private void fetchWithTask() {
new AsyncTask<Void, Integer, List<String>>() {
#Override
protected List<String> doInBackground(Void... params) {
return fetchResultsFromWebServer();
}
#Override
protected void onPostExecute(List<String> strings) {
// show the results on the UI
}
#Override
protected void onProgressUpdate(Integer... values) {
// update a progress bar here
}
}.execute();
}
It doesn't differ much by lines of code, but it's much more obvious what needs to happen and where. It protects you from nasty mistakes like forgetting to wrap UI-touching code in a Runnable that has to be posted to a UI-Thread-owned Handler.
Now imagine that you have several different types of small background tasks that need to be performed. It would be very easy to call the wrong showProgress or workFinished method from the wrong background Thread because you have to plug all those pieces together yourself.
There's also a very nasty bug lurking in the use of Handler's default constructor. If the containing class is first referenced by a non-UI thread during runtime, the Handler would belong to that Thread. AsyncTask hides always does things on the correct Thread. This is hard to catch!
At first blush AsyncTasks don't seem all that useful, but the callback plumbing is where they really pay off in spades.
"instead of using a new thread() and write the necessary background functionality?"
Why rewrite the background functionality? AsyncTask does it for you. As njk2 mentioned a Service is not really a fair comparison, though IntentService automatically creates a new thread for you in onHandleIntent().
edit: To answer your other questions, blocking the UI thread, will block all user interaction and the app will appear to "freeze". Definitely not something we want to do at all.

AsyncTask Not Updating on UI thread

I have an AsyncTask updating an ActionBarSherlock progress implementation. Somehow the onProgressUpdate is throwing a threading error though it claims to execute on the UI thread.
protected void onProgressUpdate(Integer... values)
{
setSupportProgress(values[0]);
}
The error is:
03-06 00:13:11.672: E/AndroidRuntime(4183): at com.anthonymandra.framework.GalleryActivity$ShareTask.onProgressUpdate(GalleryActivity.java:476)
Only the original thread that created a view hierarchy can touch its
views.
As far as I can tell I should be accessing the UI thread for this...
I have many working AsyncTasks in my app, but as requested here's the doInBackground (simplified):
for (MediaObject image : toShare)
{
BufferedInputStream imageData = image.getThumbStream();
File swapFile = getSwapFile(...);
write(swapFile, imageData);
++completed;
float progress = (float) completed / toShare.size();
int progressLocation = (int) Math.ceil(progressRange * progress);
onProgressUpdate(progressLocation);
}
Okay so the problem is you are calling onProgressUpdate when you should call publishProgress. The OP figured out this himself/herself so I just copy pasted it so he/she does not need to wait to accept the answer. Below is information how AsyncTasks works and it is good knowledge.
Are you creating the AsyncTask on the UI thread? If you are not that is the problem. onProgressUpdate will be run on the thread that created the AsyncTask.
Update: Let us have some code digging time (API 15 source code)!
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
This fellow will call it's static Handler sHandler. The documentation says:
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Thanks to Bruno Mateus with his documentation look-up skills:
Look that, i found at documentation page: Threading rules - There are
a few threading rules that must be followed for this class to work
properly: - The AsyncTask class must be loaded on the UI thread. This
is done automatically as of JELLY_BEAN. - The task instance must be
created on the UI thread. execute(Params...) must be invoked on the UI
thread. - Do not call onPreExecute(), onPostExecute(Result),
doInBackground(Params...), onProgressUpdate(Progress...) manually. -
The task can be executed only once (an exception will be thrown if a
second execution is attempted.)
You can declare your AsyncTask as a innerclass of your activity like that:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
I was manually calling:
onProgressUpdate
You should call
publishProgress
Easy mistake, but great info. Simon and Bruno deserve the credit, post the answer if you like. Thanks for the fast and extensive response!

AsyncTask to call another function within class

Basically, do I have to put code I want to run on another thread inside doInBackground, or can I call another function/class/whatever-it-is-functions-are-called-in-JAVA within doInBackground and have it run asynchronously? IE: (example code I found online)
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
return null;
}
is how I have seen it done, but can I instead do:
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
and have it call a function I already wrote and then have that function run in another thread? Sometimes my HTTP server is a bit slow to respond (it is but a lowly testing server at the moment) and Android automatically pops up the kill process box if my postToServer() call takes more than 5 seconds, and also disables my UI until the postToServer() call finishes. This is a problem because I am developing a GPS tracking app (internally for the company I work for) and the UI option to shut the tracking off freezes until my postToServer() finishes, which sometimes doesn't ever happen. I apologize if this has been answered, I tried searching but haven't found any examples that work the way I'm hoping to make this work.
You can do that, but you will have to move the UI updates to onPostExecute as it is run on the UI thread.
public MyAsyncTask extends AsyncTask<foo, bar, baz> {
...
protected String doInBackground(String... params) {
postToServer(x,y,z,h);
}
protected void onPostExecute(Long result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
....
}
You may want to pass in the TextView to the constructor of the AsyncTask and store it as a WeakReference.
private final WeakReference textViewReference;
public MyAsyncTask(TextView txt) {
textViewReference = new WeakReference<TextView>(txt);
}
And then in onPostExecute you would make sure that the TextView reference still exists.
protected void onPostExecute(Long result) {
TextView txt = textViewReference.get();
if (txt != null)
txt.setText("Executed");
}
If you want to notify the user that the task is executing I would put that before invoking the AsyncTask.
myTextView.setText("Update in progress...");
new MyAsyncTask().execute();
then in onPostExecute set the TextView to say "Update complete."
Have you tried it the second way?
From what you've posted it seems like it should work fine how you have it in the second example.
However (perhaps unrelated to your question?) in your first example I think it will fail because you are trying to change the UI from a background thread. You'd want to put the parts that manipulate the TextView inside of onPostExecute() rather than doInBackground()
Yes you can, the call to your postToServer method (that's the name in java) will run off the main thread.
Everything inside the doInBackground method of an AsyncTask is run on a pooled thread, but be sure to NOT invoke it directly! Call execute on your asynktask instead, the android framework will do the work for you and run doInBackground on another thread.
try doing something like this:
new AsyncTask<Void, Void, Void>() {
#Override
// this runs on another thread
protected Void doInBackground(Void... params) {
// assuming x, y, z, h are visible here
postToServer(x, y, z, h);
return null;
}
#Override
// this runs on main thread
protected void onPostExecute(Void result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
}
}.execute(); // call execute, NOT doInBackGround
Also, notice that every other method of AsyncTask, such as onPostExecute runs on the main thread, so avoid heavy loading them.
Basically The Bottom Line Is the doInBackground() method is Can't interact with The Ui Thread Or The Main thread. that's Why When You are Try To Interact With The TextView in doInBackground () it Will Crash the UI Thread Cuz It's Illegal.
so if anytime You want to Interact with the UI Thread,When You are Working on doInBackground You need to Override
OnPostExecute() //this Function is Called when The doInBackground Function job is Done.
So You can Update The UI Thread Content By this When You're Job is Done In doInBackground () or You are In doInBackground ()

Android: got CalledFromWrongThreadException in onPostExecute() - How could it be?

I have an app in production for a few weeks, using ACRA, and I had zero errors until one strange error reported today.
I've got:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
coming from this method in the stack trace (retraced):
at my.app.CountdownFragment$1.void onPostExecute(java.lang.Object)(SourceFile:1)
And this is the relevant source snippet:
private void addInstructionsIfNeeded() {
if (S.sDisplayAssist) {
new AsyncTask<String, Void, String>() {
#Override
protected String doInBackground(String... params) {
return null;
}
/*
* runs on the ui thread
*/
protected void onPostExecute(String result) {
Activity a = getActivity();
if (S.sHelpEnabled && a != null) {
in = new InstructionsView(a.getApplicationContext());
RelativeLayout mv = (RelativeLayout) a
.findViewById(R.id.main_place);
mv.addView(in.prepareView());
}
};
}.execute("");
}
}
Where addInstructionsIfNeeded() is called from a handler dispatched message (the UI thead).
onPostExecute() runs on the UI thread, so why I've got "wrong thread"?
This code ran already on more than 150 devices, and more than 100000 times (according to Flurry), and never had this error.
The originating device is Samsung SGH-I997 running SDK 4.0.4
My question is: How could it be?
EDIT:
This all happens in a fragment
i was suffering from the same problem, this is another android framework bug...
what is happening:
in certain circumstances an application can have more than one "looper" and therefore more than one "UI thread"
--side note-- i am using the term "UI thread" in the loosest of senses in this answer, since when people say "UI thread" they usually mean main or entry thread, Android like many of other OS before it, allow for for multiple message pumps (called a Looper in Android, see: http://en.wikipedia.org/wiki/Event_loop) for different UI trees, as such android for all intents and purposes is capable of running more than one "UI thread" in certain circumstances and using that term leads to rampant ambiguities... --end side note--
this means:
since an application can have more than one "UI thread" and an AsyncTask always "Runs on the UI thread" [ref], someone decided [poorly] that instead of the AsyncTask always running on its creation thread (which in 99.999999% of cases would be the correct "UI thread") they decided to use hocus pocus (or a poorly crafted shortcut, you decide) to execute on the "main looper"..
example:
Log.i("AsyncTask / Handler created ON: " + Thread.currentThread().getId());
Log.i("Main Looper: " + Looper.getMainLooper().getThread().getId() + " myLooper: "+ Looper.myLooper().getThread().getId());
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
Log.i("doInBackground ran ON: " + Thread.currentThread().getId());
// I'm in the background, all is normal
handler.post(new Runnable() {
#Override
public void run() {
Log.i("Handler posted runnable ON: " + Thread.currentThread().getId());
// this is the correct thread, that onPostExecute should be on
}
});
return null;
}
#Override
protected void onPostExecute(Void result) {
Log.i("onPostExecute ran ON: " + Thread.currentThread().getId());
// this CAN be the wrong thread in certain situations
}
}.execute();
if called from the bad situation described above the output will look something like this:
AsyncTask / Handler created ON: 16
Main Looper: 1 myLooper: 16
doInBackground ran ON: 12
onPostExecute ran ON: 1
Handler posted runnable ON: 16
that's a huge FAIL for AsyncTask
as shown this can be mitigated using a Handler.post(Runnable) in my specific case the duality of my "UI thread" situation was caused by the fact that I was creating a dialog in response to a JavaScript interface method called from a WebView, basically: the WebView had its own "UI thread" and that was the one that i was currently running on..
from what i can tell (without really caring about or reading into it too much) it seems that the AsyncTask class' callback methods in general run off a single statically instantiated handler (see: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/os/AsyncTask.java#AsyncTask.0sHandler), which means that it is always going to execute on the "main thread" or "entry thread" which they incorrectly refer to as the "UI thread" (which is presumed as any thread where UI interactions take place, eg. multiple threads in this case) this is both shoddy craftsmanship and shoddy documentation from the android team... weak sauce, the sauce is weak
hope this helps you -ck
Had the same issue. Solved in my case
Briefly explanation:
Running AsynckTask for the very first time on non UI thread with looper leads to loading AsyncTask.class and initialization sHandler to handler constructed on that non UI looper.
Now sHandler is connected to that non UI thread for ANY instance of AsyncTask subclasses and onPreExecute, onProgressUpdate and onPostExecute methods will be invoked on that non UI thread (unless AsyncTask.class will be unloaded)
Any attempt to deal with UI inside any of the above methods will lead to crash with android.view.ViewRootImpl$CalledFromWrongThreadException
To avoid such situation one should always run (at least for the very first time) AsyncTask on UI thread in order to let AsyncTask's sHandler-field be initialized with UI's looper
The story:
There were two production apps: A - main android app and B - some utilty app.
After integration app B ito app A we received a lot of crashes:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
for method running from AsynckTask.onPostExecute()
After some investigation it appeared that utility app B used AsyncTask within its HandlerThread
The traces was found in AsyncTask's source code:
private static final InternalHandler sHandler = new InternalHandler();
This is the handler which is used to send onPostExecute() to UI thread.
This handler is static and it will be initialized during class loading i.e. first new AsyncTask() appearance
It means that onPostExecute will always be posted to that thread where new AsyncTask() was called for the first time (unless AsyncTask.class will be unloaded and loaded again)
In my case the flow was something like this:
1 - starting app A
2 - initializing B form A
3 - B creates its own HandlerThread and launches AsyncTask <- now onPostExecute wil be posted to this HandlerThread no matter where from an instance of AsyncTask will be launched in future
4 - create AsyncTask in the app A for a long operation and update UI in its onPostExecute
5 - when executing onPostExecute() the CalledFromWrongThreadException is thrown
Then a friend of mine showed me related documentation from android.developers (Threading rules section):
The AsyncTask class must be loaded on the UI thread. This is done
automatically as of JELLY_BEAN. The task instance must be created on
the UI thread. execute(Params...) must be invoked on the UI thread.
Hope it can help to make clear the situation)
Maybe the reason is Flurry?
I had this exception when I used Flurry 3.2.1. But when I went back to Flurry 3.2.0 I didn't have this exception
Use Flurry 3.2.2 and above.
Placing the following line of code in the Application onCreate should solve the problem:
/**
* Fixing AsyncTask Issue not called on main thread
*/
try {
Class.forName("android.os.AsyncTask");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
It seems the issue is created when the AsyncTask class is first initiated on a different main Thread which is not our main Thread, I checked it by adding the code in the bottom, to my Application onCreate
new Thread(new Runnable() {
#Override
public void run() {
Log.i("tag","1.3onPostExecute ran ON: " + Thread.currentThread().getId());
Looper.prepare();
new AsyncTask<Void,Void,Void>(){
#Override
protected Void doInBackground(Void... params) {
Log.i("tag","2onPostExecute ran ON: " + Thread.currentThread().getId());
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Log.i("tag","1.2onPostExecute ran ON: " + Thread.currentThread().getId());
super.onPostExecute(aVoid);
}
}.execute();
Looper.loop();
Looper.myLooper().quit();
}
}).start();
This code will init the AsynTask in a main Thread which is not the application main, and will cause the application to crash in any other AsyncTask which will do any UI on the post-execute. crashing with the CalledFromWrongThreadException
Hope it cleared things a little bit more.
Thanks all for the great help on this.
Where is
runOnUiThread(new Runnable() {
public void run() { /*code*/ } );
in your code
/*
* runs on the ui thread
*/
protected void onPostExecute(String result) {
Activity a = getActivity();
if (S.sHelpEnabled && a != null) {
in = new InstructionsView(a.getApplicationContext());
runOnUiThread(new Runnable() {
public void run() {
RelativeLayout mv = (RelativeLayout) a
.findViewById(R.id.main_place);
mv.addView(in.prepareView());
}
}
};
Try this code. I think this would fix the problem
I think the problem lies in the line Activity a = getActivity(); I think you should do that before going into the AsyncTask

Update UI from Thread in Android

I want to update my UI from a Thread which updates a Progressbar. Unfortunately, when updating the progressbar's drawable from the "runnable" the progressbar disappears!
Changing the progressbars's drawable in onCreate() on the otherside works!
Any Suggestions?
public void onCreate(Bundle savedInstanceState) {
res = getResources();
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/
handler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run()
{
//* The Complete ProgressBar does not appear**/
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
}
});
}
}
You should do this with the help of AsyncTask (an intelligent backround thread) and ProgressDialog
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called begin, doInBackground, processProgress and end.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Threading rules
There are a few threading rules that must be followed for this class to work properly:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Example code
What the adapter does in this example is not important, more important to understand that you need to use AsyncTask to display a dialog for the progress.
private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(viewContacts.this);
dialog.setMessage(getString(R.string.please_wait_while_loading));
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
/* (non-Javadoc)
* #see android.os.AsyncTask#doInBackground(Params[])
*/
#Override
protected ContactsListCursorAdapter doInBackground(Void... params) {
cur1 = objItem.getContacts();
startManagingCursor(cur1);
adapter1 = new ContactsListCursorAdapter (viewContacts.this,
R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});
return adapter1;
}
protected void onPostExecute(ContactsListCursorAdapter result) {
list.setAdapter(result);
dialog.dismiss();
}
}
The most simplest solution I have seen to supply a short
execution to the UI thread is via the post() method of a view.
This is needed since UI methods are not re-entrant. The
method for this is:
package android.view;
public class View;
public boolean post(Runnable action);
The post() method corresponds to the SwingUtilities.invokeLater().
Unfortunately I didn't find something simple that corresponds to
the SwingUtilities.invokeAndWait(), but one can build the later
based on the former with a monitor and a flag.
So what you save by this is creating a handler. You simply need
to find your view and then post on it. You can find your view via
findViewById() if you tend to work with id-ed resources. The resulting
code is very simple:
/* inside your non-UI thread */
view.post(new Runnable() {
public void run() {
/* the desired UI update */
}
});
}
Note: Compared to SwingUtilities.invokeLater() the method
View.post() does return a boolean, indicating whether the
view has an associated event queue. Since I used the
invokeLater() resp. post() anyway only for fire and forget,
I did not check the result value. Basically you should
call post() only after onAttachedToWindow() has been called
on the view.
Best Regards
If you use Handler (I see you do and hopefully you created its instance on the UI thread), then don't use runOnUiThread() inside of your runnable. runOnUiThread() is used when you do smth from a non-UI thread, however Handler will already execute your runnable on UI thread.
Try to do smth like this:
private Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
res = getResources();
// pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works**
mHandler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
pB.invalidate(); // maybe this will even not needed - try to comment out
}
};
Use the AsyncTask class (instead of Runnable). It has a method called onProgressUpdate which can affect the UI (it's invoked in the UI thread).
You need to create a Handler in the UI thread and then use it to post or send a message from your other thread to update the UI
If you don't like the AsyncTask you could use the observer pattern. In that example use the ResponseHandler as an inner class in your activity then have a string message that will set the progress bars percentage... You would need to make sure that any alterations to the UI are performed within the ResponseHandler to avoid freezing up the UI, then your worker thread (EventSource in the example) can perform the tasks required.
I would use the AsyncTask tho, however the observer pattern can be good for customization reasons, plus its easier to understand. Also im not sure if this way is widely accepted or will 100% work. Im downloading and the android plugin now to test it
As recommended by official documentation, you can use AsyncTask to handle work items shorter than 5ms in duration. If your task take more time, lookout for other alternatives.
HandlerThread is one alternative to Thread or AsyncTask. If you need to update UI from HandlerThread, post a message on UI Thread Looper and UI Thread Handler can handle UI updates.
Example code:
Android: Toast in a thread

Categories

Resources