This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
AsyncTask block UI threat and show progressbar with delay
I want to show a progressDialog while retrieving JSON from any server. So I had used AsyncTask as a solution (not sure any different way out).
Everything is fine, the ProgressDialog works properly until I call .get() method using AsyncTask instance. I suppose it's blocking UI somehow. Here is my AsyncTask:
public class myAsync extends AsyncTask<String, String, List> {
String message; // for dialog message
ProgressDialog progress;
Intent myIntent;
Context ctx;
public myAsync(String message, Context ctx) {
this.message = message;
this.ctx = ctx;
progress = new ProgressDialog(ctx);
}
#Override
protected void onPreExecute() {
progress.setMessage(message);
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.show();
}
#Override
protected List doInBackground(String... params) {
//returns any list after the task
return anyList;
}
#Override
protected void onPostExecute(List result) {
if(progress.isShowing())
progress.dismiss();
}
}
And here is myActivity which is calls AsyncTask:
myAsync asyncTask = new myAsync("Loading...", this);
asyncTask.execute("Any string", "Other string");
asyncTask.get(); // If I comment out this line, ProgressDialog works
After execute, when I tried to log the result from doInBackground and onPostExecute both there is no problem. But if I want to get with .get() the result ProgressDialog is not shown or shown so little time (maybe 0.2 seconds)
What's the problem?
Yes, get() waits if necessary for the computation to complete, and then retrieves its result. This means, that you are blocking your UI thread, waiting for the result.
Solution: Don't call get
Usually, you will call a function (callback) in the postExecute.
Calling .get() changes your AsyncTask into an effective "SyncTask" as it causes the current thread (which would be the UI thread) to wait until the AsyncTask has finished its processing. Since you are now blocking the UI thread the call to the ProgressDialog's .show() method never gets a chance to allow the dialog to draw itself the screen.
Removing the call will allow it to run properly in the background.
If you need to do processing after the task has completed I suggest you either put it inside the onPostExecute method itself or use a callback to the Activity from onPostExecute.
If I understand your question correctly, you need to update the progress of your AsyncTask in a ProgressDialog and this isn't currently working. So a couple of things to note: I'm not sure what you're trying to achieve with .get() but I'll assume you want to display the progress.
I've modified your program below to update the UI thread with your AsyncTask's progress. Everytime you need to update the progress, update that prog variable in the doInBackground method.
public class myAsync extends AsyncTask<String, Integer, List> {
String message; // for dialog message
ProgressDialog progress;
Intent myIntent;
Context ctx;
public myAsync(String message, Context ctx) {
this.message = message;
this.ctx = ctx;
progress = new ProgressDialog(ctx);
}
#Override
protected void onPreExecute() {
// Runs on the UI thread
progress.setMessage(message);
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.show();
}
#Override
protected List doInBackground(String... params) {
// Runs in the background thread
// publish your progress here!!
int prog = 5; // This number will represent your "progress"
publishProgress(prog);
return anyList;
}
protected void onProgressUpdate(Integer... progress) {
// Runs in the UI thread
// This method will fire (on the UI thread) EVERYTIME publishProgress
// is called.
Log.d(TAG, "Progress is: " +progress);
}
#Override
protected void onPostExecute(List result) {
// Runs in the UI thread
for (int i=0; i<result.size(); i++) {
Log.d(TAG, "List item: " + result.get(i));
}
if(progress.isShowing())
progress.dismiss();
}
}
Try using runOnUiThread like this:
runOnUiThread(new Runnable(){
public void run() {
dialog.show();
}});
Running something on a AsyncTask means that its running away from the UIthread so usually you cant run ui operations from inside Async methods without handlers and stuff which I usually stay away from. I also handle such a solution by creating a progressDialog as a variable in my class above my oncreate so its visible to the whole class. I then call the progressdialog right before my asynctask and then since its visible to the whole class I call .dissmiss() in the onPostExecute
Related
I am writing a Android application which reads data from a SQLite Database and then displays the data on a next screen. Whenever I was doing a query on the database I would get an error message that too much work is being done on the main thread.
I then put my query in a new Thread:
(new Thread()
{
public void run()
{
Looper.prepare();
try
{
FPJobCardWizard data = dbHelperInstance.loadFPJobCardWizardFull(fitmentHash);
wState.fitmentItemSet(data.fitmentItemGet());
} catch (Exception e) {e.printStackTrace();}
Looper.loop();
}
}).start();
Now the gui/main thread is completing it's operation prior to the Query being complete and as a result the data variable is still empty. I read a few posts and the API documentation and it seems that I need to use a Looper (this seems to be the correct fix) but I have never used a Looper and cannot seem to get it to work.
Please can you check the code above and guide me in the right direction.
Thank you all in advance.
the best choice here will be using an AsyncTask, as it will enables you to perform all the background work in a background thread, then when the result is generated it will apply it using the UI thread:
So, as explained in the life cycle of AsyncTask, you can do all of your background work in the method doInBackground() and then do all of your UI work on the method onPostExecute() which will be executed after taking the result from doInBackground() method according to the life cycle, and to put your hands more on the AsyncTask, have a look at this example which provides the following example code:
public class AsyncTaskTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// This starts the AsyncTask
// Doesn't need to be in onCreate()
new MyTask().execute("my string paramater");
}
// Here is the AsyncTask class:
//
// AsyncTask<Params, Progress, Result>.
// Params – the type (Object/primitive) you pass to the AsyncTask from .execute()
// Progress – the type that gets passed to onProgressUpdate()
// Result – the type returns from doInBackground()
// Any of them can be String, Integer, Void, etc.
private class MyTask extends AsyncTask<String, Integer, String> {
// Runs in UI before background thread is called
#Override
protected void onPreExecute() {
super.onPreExecute();
// Do something like display a progress bar
}
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
String myString = params[0];
// Do something that takes a long time, for example:
for (int i = 0; i <= 100; i++) {
// Do things
// Call this to update your progress
publishProgress(i);
}
return "this string is passed to onPostExecute";
}
// This is called from background thread but runs in UI
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Do things like update the progress bar
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Do things like hide the progress bar or change a TextView
}
}
}
I use asynctask quite often however this time it doesn't work!
I have a UI contains a viewpager and fragments. To populate the view, it takes about 3 secs. Now I want to show the ProgressDialog until it finishes by using AsyncTask. But the ProgressDialog is not showing!!!!
Anybody can tell me the solution? Thanks
onCreate(...){
setContentView(...)
new LoadUI(MyActivity.this).execute();
}
public class LoadUI extends AsyncTask<Void, Void, Void>{
ProgressDialog pd;
Context context;
public LoadUI(Context mContext) {
this.context = mContext;
pd = new ProgressDialog(mContext);
aViewPager = (ViewPager) findViewById(R.id.aPagerDay);
}
#Override
protected void onPreExecute() {
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
//Create ViewPager
//Create pagerAdapter
return null;
}
#Override
protected void onPostExecute(Void result) {
if (pd.isShowing()) {
pd.dismiss();
}
super.onPostExecute(result);
}
}
You can try out two options:
Either use the AsyncTask's method get(long timeout, TimeUnit unit) like that:
task.get(1000, TimeUnit.MILLISECONDS);
This will make your main thread wait for the result of the AsyncTask at most 1000 milliseconds.
Alternatively you can show a progress dialog in the async task until it finishes. See this thread. Basically a progress dialog is shown while the async task runs and is hidden when it finishes.
You have even third option:" if Thread is sufficient for your needs you can just use its join method. However, if the task is taking a long while you will still need to show a progress dialog, otherwise you will get an exception because of the main thread being inactive for too long.
The problem is the GUI is not ready in onCreate(). And nothing will be shown if I try to show Dialog in this state. A solution is move the dialog to activity onStart():
#override
onStart(){
new LoadUI(MyActivity.this).execute();
}
Now I am doing an Android application.In my application I have to get the data from json page.This operation is taking time delay.So I have to show a progressbar until the fetching process is completed.I used the following code to show progressbar.
public void onCreate(Bundle savedInstanceState) {
//somecode
ProgressDialog progressBar = new ProgressDialog(this);
progressBar.setCancelable(true);
progressBar.setMessage("Loading");
progressBar.show();
Thread thread = new Thread(this);
thread.start();
}
public void run() {
flag=GetFixtureDetailsJsonFunction();
handler.sendEmptyMessage(0);
}
protected boolean GetFixtureDetailsJsonFunction() {
//json parsing code
return true
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (flag==true) {
progressBar.dismiss();
}
}
};
Using this code I am getting exception.android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
AsyncTask is best way for getting response from xml or database. try like this,
private class DownloadQuestion extends AsyncTask<String, Void, String>
{
#Override
protected void onPreExecute()
{
pd = ProgressDialog.show(Activity_SplashScreen.this, "","Please wait...", true,false);
super.onPreExecute();
}
#Override
protected String doInBackground(String... urls)
{
//Write background code here Code
return "";
}
#Override
protected void onPostExecute(String response1)
{
//Some Code.....
if (pd != null && pd.isShowing())
pd.dismiss();
}
}
Instead i would suggest you to implement AsyncTask, which is known as Painless Threading in android.
Using this AsyncTask, you don't need to bother about managing Threads. And its easy!!
FYI, do as follows:
Display ProgressBar in onPreExecute() method.
Do long running tasks inside the doInBackground() method.
Dismiss the ProgressBar inside the onPostExecute() method. You can also do display kinds of operation in this method.
This is a bit strange way to implement this functionality. Instead of fixing that code I suggest you using AsyncTask, which was implemented right for that purpose. See here.
You are trying to access the UI View from another thread which is not eligible.In this case this is your handler.
Instead of trying to access UI thread like this you should use an AsyncTask and do your progressDialog logic in it.
Start showing the progress bar onPreExecute
doInBackground() jobs while progressBar showing
And finallly dismiss your progressBar after your doInBackground() is complete onPostExecute()
Tips or ideas on how ProgressDialog can communicate with asyncTask.
For example when I click the button, the program will validate the input to internet, This is should not be interupted. so I use ProgressDialog.
After progressDialog.dismiss(), I need to refresh the view by calling the asyncTask.
I have tried some ways but it's failed, for example
* I execute asynTask after progressdialog.dismiss().
* put execution asynctask inside dialogbox after progressdialog thread.
in other word, is there any way to tell asynctask that progressdialog has been dismissed. Or is there communication such as message between threads ?
here is the example of my code:
btnPost.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
stockProgressDialog = ProgressDialog.show(PostActivity.this,
"Please wait...", "Check the post");
new Thread() {
public void run() {
try{
/* Connect to Internet API */
stockProgressDialog.dismiss();
} catch (Exception e) { }
// Dismiss the Dialog
}
}.start();
new LookUpTask().execute();
}
});
Yes, there is a way to tell asyncTask that progressDialog has been dismissed. you can use one onDismissListener
#Override
public Dialog onCreateDialog(int id){
if(id==DIALOG_PROGRESS_DIALOG){
stockProgressDialog = new ProgressDialog(Main.this);
stockProgressDialog.setTitle("Please wait...");
stockProgressDialog.setMessage("Check the post");
stockProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
textView.setText("Waiting the 5 secs...");
myAsyncTask.execute("start it");
//Or myAsyncTask.cancel(true); if you want to interrupt your asyncTask
}
});
return stockProgressDialog;
} else return super.onCreateDialog(id);
}
You can cancel an AsyncTask by calling AsyncTask.cancel(..) and then start up a new AsyncTask. You are not supposed to run the AsyncTask as a parallel activity - it is supposed to be able to run and finish without outside intervention.
Extend async and look into returning a result from doInBackground. onProgress update can dismiss your Progress dialog under control of the async task. Handle the result from doInBackground in onPostExecute.
//create the task
theBackground = new Background();
theBackground.execute("");
--------
private class Background extends AsyncTask<String, String, String>{
protected String doInBackground(String...str ) {
publishProgress("##0");
//do a bunch of stuff
publishProgress(#001);
return("true");
}
protected void onProgressUpdate(String... str ) {
//do stuff based on the progress string and eventually
myProgressDialog.dismiss();
}
protected void onPostExecute(String result) {
}
}
I'm not sure why you're using a thread in one case, but an AsyncTask in another when you could just use two AsyncTasks... Actually, unless I'm missing something, in your case the most straightforward way is to combine the two bits of work into one AsyncTask and simply create and destroy the dialog in the AsyncTask callbacks. In pseudo-code:
onPreExecute
show dialog
doInBackground
do internet stuff
onPostExecute
update views
close dialog
Is there a reason why you're trying to update the views in its own AsyncTask? If you're updating views, you probably need to do the work in the UI thread anyway...
I've got an Android activity which grabs an RSS feed from a URL, and uses the SAX parser to stick each item from the XML into an array. This all works fine but, as expected, takes a bit of time, so I want to use AsyncActivity to do it in the background. My code is as follows:
class AddTask extends AsyncTask<Void, Item, Void> {
protected void onPreExecute() {
pDialog = ProgressDialog.show(MyActivity.this,"Please wait...", "Retrieving data ...", true);
}
protected Void doInBackground(Void... unused) {
items = parser.getItems();
for (Item it : items) {
publishProgress(it);
}
return(null);
}
protected void onProgressUpdate(Item... item) {
adapter.add(item[0]);
}
protected void onPostExecute(Void unused) {
pDialog.dismiss();
}
}
Which I call in onCreate() with
new AddTask().execute();
The line items = parser.getItems() works fine - items being the arraylist containing each item from the XML. The problem I'm facing is that on starting the activity, the ProgressDialog which i create in onPreExecute() isn't displayed until after the doInBackground() method has finished. i.e. I get a black screen, a long pause, then a completely populated list with the items in. Why is this happening? Why isn't the UI drawing, the ProgressDialog showing, the parser getting the items and incrementally adding them to the list, then the ProgressDialog dismissing?
I suspect something is blocking your UI thread after you execute the task. For example, I have seen folks do things like this:
MyTask myTask = new MyTask();
TaskParams params = new TaskParams();
myTask.execute(params);
myTask.get(5000, TimeUnit.MILLISECONDS);
The get invocation here is going to block the UI thread (which presumably is spinning off the task here...) which will prevent any UI related stuff in your task's onPreExecute() method until the task actually completes. Whoops! Hope this helps.
This works for me
#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();
}
It is because you used AsyncTask.get() that blocks the UI thread "Waits if necessary for the computation to complete, and then retrieves its result.".
The right way to do it is to pass Activity instance to your AsyncTask by constructor, and finish whatever you want to do in AsyncTask.onPostExecution().
If you subclass the AsyncTask in your actual Activity, you can use the onPostExecute method to assign the result of the background work to a member of your calling class.
The result is passed as a parameter in this method, if specified as the third generic type.
This way, your UI Thread won't be blocked as mentioned above. You have to take care of any subsequent usage of the result outside the subclass though, as the background thread could still be running and your member wouldn't have the new value.