In an activity I load rows of a listview which takes much time, therefore I put this task in a separate thread to allow displaying a progressDialog.
I do the following
private void doMyStuff() {
listItems.clear();
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
for () {
listItems.add(something to add);
}
handler.sendEmptyMessage(0);
progressDialog.dismiss();
}
}).start();
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0) {
adapter.notifyDataSetChanged();
}
};
};
I have sometimes a bug which raises an IllegalStateException. First of all I was surprised, because programming thread like that is what I usually do in standard Java programs.
The bug appears only "sometimes" and it does not appear when doing step by step debugging.
This lead me to search around the web and I found some questions in SO related to this and I must admit that things are not clear to my mind.
As I call the notifyDataSetChanged() only when the thread finished why does it sometimes raises an exception.
Can someone confirm me that this way of doing is wrong, and that I MUST use async task and perhaps explain me why ???
I need to have a progressDialog displayed, can someone give me a simple example of AsyncTask populating a listview AND displaying a progressDialog of the populating progress.
Thanks
UPDATE
jtanveer gave me the answer to the asynctask question. Now the others pointed out that the dismiss is not in the handler, which I correct.
According to the article given by jtanveer on "Painless Threading" they say that
Android offers several ways to access the UI thread from other threads which one of them is HANDLER.
Does someone know why putting the dismissed in the handler did not solve my problem ? for me listItem.add has nothing to do with UI ? Am I wrong on that point ?
For me, in my code the only UI is adapter and progressdialog ? Any commentary or explanation is welcome.
FINAL ANSWER
stjom gave a working answer for my specific code. Running the runOnUiThread in the handler. It's working but I am surprised because I thought the handler was run in the Ui Thread ...
Thanx to all for all your answers.
define an inner class like below:
private class LoadListTask extends AsyncTask<String, Void, Integer> {
protected void onPreExecute() {
progressDialog.show();
}
protected Integer doInBackground(String... params) {
for () {
listItems.add(something to add);
}
return 0;
}
protected void onPostExecute(Integer result) {
progressDialog.dismiss();
if (result == 0) {
adapter.notifyDataSetChanged();
}
}
}
if you need, you can refer to this article.
whenever you call adapter.notifyDataSetChanged(); it identifies any changes to your listItems object. if any change is found, it will update the UI accordingly which I think causes your problem. you can call
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
inside your handler.
You don't need to use AsyncTask, its just a convenience.
As far as why your current implementation doesn't work sometimes -
You should dismiss your progress dialog from the UI thread, so that needs to go in your handler, not your background thread.
Related
Here is my code for Progress Dialog in Android and i am getting following error:android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. I saw all previous post related to this error but i could not correct this error.
// Waiting screen
pleaseWaitdialog = ProgressDialog.show(PhoneBookListView.this, "Loading", "Please wait...", true);
new Thread(new Runnable() {
#Override
public void run()
{
Looper.prepare();
// do the thing that takes a long time
LoadContactFromPhoneAndSim();
PhoneBookListView.this.runOnUiThread(new Runnable() {
#Override
public void run()
{
pleaseWaitdialog.dismiss();
}
});
}
}).start();
Any help will be appreciate
Thanks.
I suggest you use an AsyncTask, as they make this sort of thing easier. In general, you want to do complex stuff on a background thread, and only update the UI from the UI thread.
public class PhonebookLoader extends AsyncTask<Void,Void,Void> {
protected Void doInBackground(Void ... params) {
LoadContactFromPhoneAndSim();
return void;
}
protected void onPostExecute(Void param) {
pleaseWaitdialog.dismiss();
}
}
To start it with this class, you just call this:
new PhonebookLoader.execute();
And you can do all kinds of things with this, like publish your progress so the user knows how far they have progressed, update the UI thread after you are done loading, etc. AsyncTask is your friend, use it.
Looking at this, I suspect that PhonebookLoader is probably both loading the data and putting it on the UI. Separating these two tasks will make your app much more responsive and easier to maintain.
I'm trying to do an Android game using a Thread which repeats a loop for draw, move and others.
I have a problem with the execution of a method, which searches a value with a "do while" loop. When this method is executed, the thread does not continue until this process does not end.
What would be the best option for avoid this? Make another thread within that method? If you can give an example I'd really appreciate it.
Here's some pseudocode:
void mainLoop(){
drawElements();
moveElements();
//...
//...
reposition();
}
void reposition(){
// this stops my thread
do{
// do stuff
}while(!end);
// do stuff
}
As wqrahd suggested use AsyncTask.
I assume mainLoop is a main UI thread.
public class RepositionClass extends AsyncTask {
private Context mContext;
public RepositionClass(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
// do UI related here, this function will run in main thread context.
}
#Override
protected Boolean doInBackground(String... params) {
// call non-ui(computation intensive) part of reposition function here.
return true;
}
#Override
protected void onPostExecute(Boolean result) {
// do UI related part of reposition function here.
}
}
Creating another thread won't help you if you still have to block and wait for the loop to complete the search. The problem really is what is happening in the "do stuff" loop, you just need to optimize that to solve the issue.
use asyntask and in asyntask's doInBackground , do your thread work and in asyntask's onPostExecute call your repositionMethod.
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.
In one activity of my app I make a bunch of edit text fields dynamically and then set them with some text from sharedpreferences. I realise that this is a bit much for the main thread to handle which is why there is some lagging of the app when it loads. I am quite new to the concept of threads so I was wondering what the best way was to put the loading of the strings from sharedpreferences into another thread and then just display a loading bar(or similar) in the meantime(in the main thread I guess). Please explain in great detail because threads are new to me.
Also if there are any tutorials on this that point me the the right direction they would also be useful. Thanks in advance.
AsyncTask is what you need.
Create a class that extends AsyncTask
Do your heavy work in doInBackground()
Example:
Class Example extends AsyncTask{
#Override
protected void doInBackground(Object... args){
//do ur stuff
}
#Override
protected void onPostExecute(Object arg){
//do what you wanna do after doInBackground
}
}
Call your task by new Example().execute();
Whilst only the main thread can make changes to the UI, you can you the AsyncTask class to do all the other work on another thread and then push things to the main thread as they are ready to be put on the UI.
YOu can have something like this: Just to guide you
final ProgressDialog pd = ProgressDialog.show(context, "Title", "Loading");
new Thread(new Runnable()
{
#Override
public void run()
{
//get data from shared preferences
runOnUiThread(new Runnable()
{
#Override
public void run()
{
pd.dismiss();
//set that text to your dynamic textview
}
});
}
}).start();
when I read document about asyntask, they say that: "should not" update UI thread in doInbackground because doInbackground work on different thread.
that means : this action will dangerous because UI Thread isn't thread-safe. I understand it. but when I try for test what happen when I update UI Thread in this function. I receive error: (but error doesn't not look like because aysnchonize, but because we CANNOT do it)
(TextView)((Activity)context).findViewById(R.id.text)).setText("StackOverFlow");
//context: reference of context object of UI Thread
Please explain for me. Does we shouldn't or mustn't .
thanks :)
what I have understand so far with android is...,
we can't update UI thread from background thread.
May be it is the case they have stopped us to update UI from background thread.
The reason for that is very clear... # OS level there will be so many thread will be running.
And also
different thread from different application, And in that case It will be chaos on the screen, if we can update UI from bg-thread
Inside the doInBackgroundyou will not get the UI access. If You Want to take UI access publishProgress from doInBackgroundyou will go to the onProgressUpdate from there do what you wan to show on UI.
Below is the Code you will check for your reference :
class DownloadAsyncTask extends AsyncTask
{
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(Login.this, "", "Please Wait ...");
}
#Override
protected Void doInBackground(String... arg0) {
int status1 = validationuser(username);
Log.i("MyLog", "Inside the doInBackground is came"+status1);
if(status1 == 1)
{
publishProgress(status1+ "Valid User Code","1",""+status1);
}
else
{
publishProgress(status1+ " Invalid Valid User Code","0",""+status1);
}
return null;
}
#Override
protected void onProgressUpdate(String...values){
super.onProgressUpdate(values);
int index = Integer.parseInt(values[2]);
if(index == 1)
{
USERIDLOGIN = edittextuserName.getText().toString();
Intent intent=new Intent(Login.this, CollectionModuleandDownload.class);
/*Toast.makeText(Login.this, "Valid User Password", Toast.LENGTH_SHORT).show();*/
startActivity(intent);
progressDialog.dismiss();
}
else
{
Toast.makeText(Login.this, "Invalid Username & Password", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
}
#Override
protected void onPostExecute(Void result){
super.onPostExecute(result);
/*if(progressDialog != null)
{
progressDialog.dismiss();
}*/
}
}
so you have to update ui only on the OnPostExecute & OnPreExecute.
here's a good example of asynctask. give it a try
you call it by
new SaveProfile().execute();
then this...
private class SaveProfile extends AsyncTask<String, Void, Boolean>{
#Override
protected Boolean doInBackground(String... params) {
//---------- so your stuff here.... non ui related
Log.v("response from saving",response);
if(response.equals("1")){
return true;
}else{
return false;
}
}
protected void onPostExecute(Boolean result) {
if(result) {
//------ UPDATE UI HERE
Toast.makeText(ProfileCompanyActivity.this, "profile saved", 2500).show();
}else{
Toast.makeText(ProfileCompanyActivity.this, "an error occured", 2500).show();
}
}
}
When you create a Aysnc task the doInBackground method runs in the separate thread from UI thread. So you cannot update the UI from this method.
The OnPostExecute and onPreExecute method execute in the same thread as UI thread. For further reading go here
If only one thread is allowed to touch the user interface, Android can guarantee that nothing vital is changed while it’s measuring views and rendering them to the screen
It is because .. User Interface can be updated only on mainthread..all the user interface objects in your screen are maintained by this mainthread....now if you try to change the user interface from some other thread(do in background)in this case.. it causes error because..for example.. if you try to change the seekbar(some widget) value from other than main thread.. and the user is trying to put a different value...then it is ambiguous for android.. as to which thread it should listen... hope it clarifies your doubt..
So, it is like we should'nt try to.. and because of its security.. we cannot try also.. as it gives error.. =]
doInBackground is used to perform heavy calculations or any background work you want to perform in your activity.
when the operation in your doinbackground method finished the on postexecute methods upadates your ui..
in short doinbackground is not used to update ui.
I think the answer is that we mustn't
It just doesn't seem logical to me..
its like trying to change the radio station at another car driving beside you..
the architecture just doesn't work that way.. you can decide on a radio station before you set off to your road trip or when you stop driving and theoretically you can yell to him and ask him to change the station but you cannot do it yourself.
As doInBackground() runs on separate thread and onPostExecute runs on UIMain thread and as per constraint provided by Android you cannot update UIMain Thread from other thread.
Because of above mentioned reason you are getting mentioned message while you are running your application.