The progress dialog in AsyncTask does not dismiss, even though progressDialog.dismiss is run in onPostExecute().
I have tried implementing many answers to related questions on SO, with no success so far.
I am sure that I must be overlooking something very basic, but I am stuck.
Any pointers to an explanation and code snippet would be great, Thanks.
Main
public class Main extends Activity {
String result;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
asyncTask task = new asyncTask("Loading ...", this);
try {
result = task.execute("Question").get();
}
catch (Exception e) {
Log.e("Error: ", e.toString());
}
}
}
asyncTask
public class asyncTask extends AsyncTask<String, Void, String> {
private ProgressDialog progressDialog;
private String message;
private Context context;
public asyncTask(String msg, Context ctx) {
this.context = ctx;
message = msg;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(context);
progressDialog.show(context, "", message, true, false);
}
#Override
protected String doInBackground(String... params) {
int count = 100000;
for (int i = 0; i < count; i++) {
// waste time
}
return "Answer";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
}
}
Actually your are doing :
progressDialog.show(context, "", message, true, false);
instead it should be like :
progressDialog = ProgressDialog.show(context, "", message, true, false);
You have to statically call show method and assign it to your progressDialog
Make this changes in your onPostExecute
#Override
protected void onPostExecute(String result) {
try{
if(progrssDialog.isShowing()){
progressDialog.dismiss();
}
}
catch(Exception e){
e.printStackTrace();
}
finally
{
progressDialog.dismiss();
}
}
A common issue i have found is the Variable Scope.
Most times , the ProgressDialog will be defined inside a Method , which wont be accessable outside that method.
You need to Declare it like so ,
Public Class MainActivity extends Activity {
ProgressDialog progressDialog;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private class asyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progressDialog.dismiss();
}
}
replace
task.execute("Question").get();
with
task.execute("Question");
by calling .get() you forcing main thread to wait. It will/can hang your UI.
progressDialog.dismiss();
put this in doInBackground() method before Return Statement.
Related
I have a progress dialog, I want it to show and dismiss when my method has finished executing. now, I have this:
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Downloading...");
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
try{
DownloadMethod(s);
progressDialog.dismiss();
}catch (Exception e){
Toast.makeText(prefs.this, "We can't reach the data...Try again", Toast.LENGTH_SHORT).show();
}
}
}).start();
My method DownloadMethod is executed but never shows the dialog.
Actually, It must be throwing an exception with progressDialog.dismiss(); call because you cannot update UI from a worker thread, instead use AsyncTask
e.g pass parameter to constructor
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
TypeOf_S s;
public DownloadFilesTask(TypeOf_S s){
this.s = s;
}
#Override
protected Void doInBackground(Void... obj) {
DownloadMethod(s);
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
}
and call it like new DownloadFilesTask(s).execute();
or with generic parameter
private class DownloadFilesTask extends AsyncTask<TypeOf_S, Void, Void> {
#Override
protected Void doInBackground(TypeOf_S... obj) {
DownloadMethod(obj[0]);
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
}
and call it like new DownloadFilesTask().execute(s);
progressDialog.dismiss();is throwing an exception so move your code inside runOnUiThread() method like this:
runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
}
});
as suggested by Pavneet you can use async task as follows where AsyncTask<String, void, String> corresponds to the input type progress value and last is result value you are interested so give data types accordingly.
private class DownloadFilesTask extends AsyncTask<String, void, String> {
protected String doInBackground(String... urls) {
//here do the actual downloading instead of calling the DownloadMethod(s)
}
protected void onPreExecute() {
//here show the dialog
progressDialog.show();
}
protected void onPostExecute(String result) {
//here hide the dialog
progressDialog.dismiss();
}
}
and where you are calling the download function you just call this
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Downloading...");
new DownloadFilesTask().execute(s);
//here s is assumed to be string type you can give anything
I'm inserting some data in my app's local database inside AysncTask, but when executing the class the progress dialog is not showing on the screen while i can see the running log. I see many related answer but the issue is not resolved. I read the .get() method blocks the ui but I'm already not using this method. I don't why it is not showing on the screen
calling async class from main Activity
AsyncGetDataFromServer task = new AsyncGetDataFromServer(this);
task.execute();
code of AsyncTask class
public class AsyncGetDataFromServer extends AsyncTask<Void, Void, Boolean> {
ProgressDialog pd;
Context cxt;
DatabaseHandler dbHelper;
private static ArrayList<DataModel> categoryArrayList;
public AsyncGetDataFromServer(Context context) {
// TODO Auto-generated constructor stub
cxt= context;
pd = new ProgressDialog(cxt);
pd.setTitle("Please wait");
pd.setMessage("Loading...");
pd.setCancelable(false);
dbHelper = new DatabaseHandler(cxt);
}
#Override
protected Boolean doInBackground(Void... params)
{
try {
Log.d("do in background","true");
for (int i = 0; i < response.body().getVideoEntity().size(); i++) {
//inserting in categories
VideoEntity videoEntity;
videoEntity = response.body().getVideoEntity().get(i);
dbHelper.insertChannels(videoEntity);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e("exception error", e.getMessage());
}
return true;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("on pre execute","true");
pd.show();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.d("on post execute","true");
pd.dismiss();
}
}
pass Activity instead of context to the constructor.For example-
AsyncGetDataFromServer task = new AsyncGetDataFromServer(MyActivity.this);
task.execute();
You should implement the method onProgressUpdate and use the method publishProgress :
see https://developer.android.com/reference/android/os/AsyncTask.html
Show dialog in onPreExecute() method & dismiss in onPostExecute() method:
private class AsyncGetDataFromServer extends AsyncTask<Void, Void, Boolean> {
private final ProgressDialog dialog = new ProgressDialog(YourClass.this);
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.show();
}
protected void doInBackground(final Void unused) {
//don't interact with the ui!
}
protected void onPostExecute(final Boolean result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
So I am completely new to Andorid programming and can't seem to get a ProgressDialog to show on a ListActivity (ScheduleActiviy in my example) when running an AsyncTask from a separate class (GetGames in my example). I am attempting to use separate class for code re-usability. When I previously had the AsyncTask as an embedded class it seemed to work. I have posted what I believe to be all the relevant code. Any help would be great. Thanks!
ScheduleActivity.java
public class ScheduleActivity extends ListActivity
{
private final String PDIALOG_MSG = "Loading schedule...";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.schedule);
ArrayList<HashMap<String, String>> gamesList = null;
try
{
// Loading information in Background Threads
gamesList = new GetGames(ScheduleActivity.this, PDIALOG_MSG).execute().get();
GetGames.java
public class GetGames extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>>
{
private Context context;
private ProgressDialog pDialog;
private String pDialogMsg;
public GetGames(Context ctx, String dialogMsg)
{
context = ctx;
pDialogMsg = dialogMsg;
}
#Override
public void onPreExecute()
{
super.onPreExecute();
pDialog = new ProgressDialog(context);
pDialog.setMessage(pDialogMsg);
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
public void onPostExecute(ArrayList<HashMap<String, String>> rtnList)
{
pDialog.dismiss();
}
Your ProgressDialog should probably be controlled on the Activity level instead of the AsyncTask level. Theoretically I don't see why how you're doing it wouldn't work, but I can show you a method which definitely works (it's what I do) and it organizes things a bit differently:
//In AsyncTask
#Override
protected void onPreExecute() {
showProgressDialog(R.string.importing_pages);
}
#Override
public void onPostExecute(Boolean b) {
hideProgressDialog();
}
//In Activity
public void showProgressDialog(int msgResId) {
showProgressDialog(getString(msgResId));
}
public void showProgressDialog(String msg) {
mProgressDialog = ProgressDialogHelper.buildDialog(this, msg);
mProgressDialog.show();
}
public void hideProgressDialog() {
if(mProgressDialog != null)
mProgressDialog.dismiss();
}
//My progress dialog helper class:
public class ProgressDialogHelper {
/**
* Creates a generic progress dialog with the specified message
*
* #param activity the activity which hosts the dialog. This must be an activity, not a context.
* #param msgResId the resId for the message to display
* #return a progress dialog
*/
public static ProgressDialog buildDialog(Activity activity, int msgResId) {
return buildDialog(activity, activity.getApplicationContext().getString(msgResId));
}
/**
* Creates a generic progress dialog with the specified message
*
* #param activity the activity which hosts the dialog. This must be an activity, not a context.
* #param msg the message to display
* #return a progress dialog
*/
public static ProgressDialog buildDialog(Activity activity, String msg) {
ProgressDialog dialog;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
dialog = new ProgressDialog(new ContextThemeWrapper(activity, android.R.style.Theme_Holo_Dialog));
else
dialog = new ProgressDialog(activity);
dialog.setMessage(msg);
dialog.setCancelable(false);
return dialog;
}
}
You don't have to make a helper class if you don't want to, it's just how I organized it. The main idea here is that the progress dialog should be owned by the Activity instead of the AsyncTask.
Also, the context used must be the activity's, not getApplicationContext(). It looks like you have that part right though.
You can display Progress Dialogs using AsyncTasks. That's not a problem. I do it all the time. What may be the problem is the doInBackground() method. What do you have there?
I also generally nest the AsyncTasks within the Activity class, so that it can call other Activity class methods in the onPostExecute() method. Otherwise, in order for it to communicate back with your Activity you'll have to use something like a handler or static references.
public class TestActivity extends Activity {
private AsyncTask<Void, Void, ArrayList<String>> bgLoader;
private ArrayList<String> listOfStuff;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
listOfStuff = new ArrayList<String>();
textView = (TextView) findViewById(R.id.textView);
textView.setText("Your list has " + listOfStuff.size() + " items in it!");
bgLoader = new MyAsyncTask(this, "Waiting...").execute();
}
private void resumeDoingStuff() {
try {
listOfStuff = bgLoader.get();
textView.setText("Your list has " + listOfStuff.size() + " items in it!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public class MyAsyncTask extends AsyncTask<Void, Void, ArrayList<String>> {
private ProgressDialog progressDialog;
private String message;
private Context ctx;
public MyAsyncTask(Context context, String message) {
this.ctx = context;
this.message = message;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(ctx);
progressDialog.setMessage(message);
progressDialog.setIndeterminate(false);
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected ArrayList<String> doInBackground(Void... params) {
ArrayList<String> retList = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
try {
retList.add("TEST STRING " + i);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return retList;
}
#Override
protected void onPostExecute(ArrayList<String> result) {
progressDialog.dismiss();
resumeDoingStuff();
}
}
}
I am trying to use progress bar while updating my database. Good thing, i can successfully update my database but my progress bar is not showing. I am using a progress bar the will show also the percentage on my update. I don't know what wrong with my code below, help me figure it out please:
public class SyncBrand extends AsyncTask<String, Void, Boolean>
{
public static final int BRAND_DIALOG_DOWNLOAD_PROGRESS = 0;
public SyncBrand(Context context, String _username, String _password, String _code,String _remarks,String _date,String _province,String _infotype,
String _competitor,ArrayList<String> _brands, ArrayList<String> _segments)
{
....
}
protected Dialog onCreateDialog(int id) {
switch (id) {
case BRAND_DIALOG_DOWNLOAD_PROGRESS:
progressDialog = new ProgressDialog(mContext);
progressDialog.setMessage("Updating Sub Brands..");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false);
progressDialog.show();
return progressDialog;
default:
return null;
}
}
#SuppressWarnings("deprecation")
protected void onPreExecute()
{
super.onPreExecute();
((Activity) mContext).showDialog(BRAND_DIALOG_DOWNLOAD_PROGRESS);
}
protected Boolean doInBackground(String... arg0)
{
try{
....
}catch (Exception e){
Log.e("Update SubBrand", "Error:", e);
exception = e;
return false;
}
....
return true;
}
protected void onProgressUpdate(String... progress) {
Log.d("ANDRO_ASYNC",progress[0]);
progressDialog.setProgress(Integer.parseInt(progress[0]));
}
#SuppressWarnings("deprecation")
protected void onPostExecute(Boolean valid)
{
((Activity) mContext).removeDialog(BRAND_DIALOG_DOWNLOAD_PROGRESS);
if(valid){
.....
}else{
Toast.makeText(mContext, "Failed to update.Please try again.", Toast.LENGTH_SHORT).show();
mContext.startActivity(new Intent(mContext, S_2nd_Main.class));
}
}
}
A couple problems I see here. You have Void for the second argument in your AsyncTask
public class SyncBrand extends AsyncTask<String, Void, Boolean>
which means that onProgressUpdate() should expect that type of data passed to it but you have protected void onProgressUpdate(String... progress) { which tells that method to take a String parameter. Also, you don't call publishProgress() from doInBackground() which is what is used to call onProgressUpdate().
Change your AsyncTask to
public class SyncBrand extends AsyncTask<String, String, Boolean>
and add publishProgress() to doInBackground() and pass the String value you want it to update the ProgressDialog to.
I'm trying to display a custom progressdialog while loading RSS feed from an HTTP server, I made a hard search, but nothing helped me to do this, the only thing I know is that the solution should use AsyncTask, but I'm confusing about the params to pass to this AsyncTask.
Here's my activity :
public class Soirees extends ListActivity {
private List<Message> messages;
private TextView tvSorties;
private MyProgressDialog dialog;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.sorties);
tvSorties=(TextView)findViewById(R.id.TVTitle);
tvSorties.setText("Programme des soirées");
loadFeed();
}
private void loadFeed(){
try{
BaseFeedParser parser = new BaseFeedParser();
messages = parser.parse();
List<Message> titles = new ArrayList<Message>(messages.size());
for (Message msg : messages){
titles.add(msg);
}
MessageListAdapter adapter = new MessageListAdapter(this,titles);
this.setListAdapter(adapter);
adapter.notifyDataSetChanged();
} catch (Throwable t){
Log.e("ImageLoader",t.getMessage(),t);
}
}
}
Can you please help me add AsyncTask to this?
/**
* this class performs all the work, shows dialog before the work and dismiss it after
*/
public class ProgressTask extends AsyncTask<String, Void, Boolean> {
public ProgressTask(ListActivity activity) {
this.activity = activity;
dialog = new ProgressDialog(activity);
}
/** progress dialog to show user that the backup is processing. */
private ProgressDialog dialog;
/** application context. */
private ListActivity activity;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
MessageListAdapter adapter = new MessageListAdapter(activity, titles);
setListAdapter(adapter);
adapter.notifyDataSetChanged();
if (success) {
Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
}
}
protected Boolean doInBackground(final String... args) {
try{
BaseFeedParser parser = new BaseFeedParser();
messages = parser.parse();
List<Message> titles = new ArrayList<Message>(messages.size());
for (Message msg : messages){
titles.add(msg);
}
activity.setMessages(titles);
return true;
} catch (Exception e)
Log.e("tag", "error", e);
return false;
}
}
}
public class Soirees extends ListActivity {
private List<Message> messages;
private TextView tvSorties;
private MyProgressDialog dialog;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.sorties);
tvSorties=(TextView)findViewById(R.id.TVTitle);
tvSorties.setText("Programme des soirées");
// just call here the task
AsyncTask task = new ProgressTask(this).execute();
}
public void setMessages(List<Message> msgs) {
messages = msgs;
}
}
Fixed by moving the view modifiers to onPostExecute so the fixed code is :
public class Soirees extends ListActivity {
private List<Message> messages;
private TextView tvSorties;
//private MyProgressDialog dialog;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.sorties);
tvSorties=(TextView)findViewById(R.id.TVTitle);
tvSorties.setText("Programme des soirées");
new ProgressTask(Soirees.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
List<Message> titles;
private ListActivity activity;
//private List<Message> messages;
public ProgressTask(ListActivity activity) {
this.activity = activity;
context = activity;
dialog = new ProgressDialog(context);
}
/** progress dialog to show user that the backup is processing. */
/** application context. */
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
List<Message> titles = new ArrayList<Message>(messages.size());
for (Message msg : messages){
titles.add(msg);
}
MessageListAdapter adapter = new MessageListAdapter(activity, titles);
activity.setListAdapter(adapter);
adapter.notifyDataSetChanged();
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
Toast.makeText(context, "OK", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
}
}
protected Boolean doInBackground(final String... args) {
try{
BaseFeedParser parser = new BaseFeedParser();
messages = parser.parse();
return true;
} catch (Exception e){
Log.e("tag", "error", e);
return false;
}
}
}
}
#Vladimir, thx your code was very helpful.
AsyncTask is very helpful!
class QueryBibleDetail extends AsyncTask<Integer, Integer, String>{
private Activity activity;
private ProgressDialog dialog;
private Context context;
public QueryBibleDetail(Activity activity){
this.activity = activity;
this.context = activity;
this.dialog = new ProgressDialog(activity);
this.dialog.setTitle("查询经文");
this.dialog.setMessage("正在查询:"+tome+chapterID+":"+sectionFromID+"-"+sectionToID);
if(!this.dialog.isShowing()){
this.dialog.show();
}
}
#Override
protected String doInBackground(Integer... params) {
Log.d(TAG,"经文doInBackground");
publishProgress(params[0]);
if(sectionFromID > sectionToID){
return "";
}
String queryBible = "action=query_bible&article="+chapterID+"&id="+tomeID+"&verse_start="+sectionFromID+"&verse_stop="+sectionToID+"";
try{
String bible = (Json.getRequest(HOST+queryBible)).trim();
bible = android.text.Html.fromHtml(bible).toString();
return bible;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String bible){
Log.d(TAG,"经文onPostExecute");
TextView bibleBox = (TextView) findViewById(R.id.bibleBox);
bibleBox.setText(bible);
this.dialog.dismiss();
}
}
A couple of days ago I found a very nice solution of this problem. Read about it here. In two words Mike created a AsyncTaskManager that mediates ProgressDialog and AsyncTask. It's very easy to use this solution. You just need to include in your project several interfaces and several classes and in your activity write some simple code and nest your new AsyncTask from BaseTask. I also advice you to read comments because there are some useful tips.
Don't know what parameter should I use?
A lot of Developers including have hard time at the beginning writing an AsyncTask because of the ambiguity of the parameters. The big reason is we try to memorize the parameters used in the AsyncTask. The key is Don't memorize. If you can visualize what your task really needs to do then writing the AsyncTask with the correct signature would be a piece of cake.
What is an AsyncTask?
AsyncTask are background task which run in the background thread. It takes an Input, performs Progress and gives Output.
ie AsyncTask<Input,Progress,Output>
Just figure out what your Input, Progress and Output are and you will be good to go.
For example
How does doInbackground() changes with AsyncTask parameters?
How doInBackground() and onPostExecute(),onProgressUpdate() are
related?
How can You write this in a code?
DownloadTask extends AsyncTask<String,Integer,String>{
#Override
public void onPreExecute(){
}
#Override
public String doInbackGround(String... params)
{
// Download code
int downloadPerc = // calculate that
publish(downloadPerc);
return "Download Success";
}
#Override
public void onPostExecute(String result)
{
super.onPostExecute(result);
}
#Override
public void onProgressUpdate(Integer... params)
{
// show in spinner, access UI elements
}
}
How will you run this Task in Your Activity?
new DownLoadTask().execute("Paradise.mp3");
It's been a few years since this question was asked (and since someone has posted a response). Since then, ProgressDialog was deprecated in API level O, according to Android's official documentation. As such, you might consider using an inline progress bar instead of a ProgressDialog as the documentation authors suggest.
This question is already answered and most of the answers here are correct but they don't solve one major issue with config changes. Have a look at this article https://androidresearch.wordpress.com/2013/05/10/dealing-with-asynctask-and-screen-orientation/ if you would like to write a async task in a better way.