Trying to display a ProgressDialog in AsyncTask executed in a MapActivity - java

I have a MapActivity that has code similar to this in onCreate():
if(...) {
...
new FirstAsyncTask(id, this).execute((Object[]) null);
...
} else {
...
myLocationOverlay.runOnFirstFix(new Runnable() {
new SecondAsyncTask(lat, lon, ActivityName.this).execute((Object[]) null);
}
...
}
The FirstAsyncTask and SecondAsyncTask both do different things, but both of them show a ProgressDialog like so:
public FirstAsyncTask(long id, Context context) {
progressDialog = new ProgressDialog(context);
}
protected void onPreExecute() {
...
progressDialog.show();
}
protected String doInBackground(Object... params) {
...
progressDialog.dismiss();
...
}
This is working with FirstAsyncTask, but no matter what I change in the call to SecondAsyncTask it always fails with this error: Can't create handler inside thread that has not called Looper.prepare(). I have tried setting the context parameter to "this", "ActivityName.this", getApplicationContext(), and getBaseContext().
I'm still pretty new to Android so this idea of a "context" is confusing me. I'm even more confused that FirstAsyncTask works but SecondAsyncTask doesn't. I've seen this error mentioned a lot in other questions but none of the answers seem to work. Any ideas?
EDIT: The exception is being thrown when the ProgressDialog is being initialized in the SecondAsyncTask's constructor.

The problem is here
myLocationOverlay.runOnFirstFix(new Runnable() {
new SecondAsyncTask(lat, lon, ActivityName.this).execute((Object[]) null);
}
SecondAsyncTask is being constructed on a newly spawned thread. not the UI thread.
Create the one progressDialog in the activity. And then access the Activity's progressDialog from the Asynctasks.
public class MyActivity extends Activity {
ProgressDialog mProgressDialog;
onCreate(...){
mProgressDialog = new ProgressDialog();
}
private class MyAsyncTask extends AsyncTask<...> {
...
onPreExecute(...){
mProgressDialog.show();
}
onPostExecute(...){
mProgressDialog.dismiss();
}
}
private class MyAsyncTask2 extends AsyncTask<...> {
...
onPreExecute(...){
mProgressDialog.show();
}
onPostExecute(...){
mProgressDialog.dismiss();
}
}
Do not attempt to perform progressDialog.dismiss() from the doInBackground, instead put it in postExecute which is running in the UI thread.
You'll want to set up flags once all this is working so that you only dismiss the progressdialog once both tasks are complete.

Write your dialogue dismiss code inside onPostExecute() method it will run the code in the UI thread
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
}
Write your AsyncTask class this way:
private class FirstAsyncTask extends AsyncTask<String, Void, Void> {
ProgressDialog myDialog = null;
#Override
protected void onPreExecute() {
myDialog = ProgressDialog.show(YourActivityClass.this, "",
"Loading Data...");
return;
}
#Override
protected Void doInBackground(String... urls) {
//Your code which you want to run in background
return null;
}
#Override
protected void onPostExecute(Void result) {
myDialog.dismiss();
return;
}
}
above code works if you have defined the AsyncTask class as inner class of the Activity. If your AsyncTask class is defined as a seperate class then you have to pass the context of the activity to its constructor
ProgressDialog myDialog = null;
Context context;
public FirstAsyncTask (Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
myDialog = ProgressDialog.show(context, "",
"Loading Data...");
return;
}

Related

Progress Dialog on Async Task

I have created Three Classes, namely Mainactivity which is passing context to server class extending to Asynctask. There one class named setting, which call server class for updating data in server.
Code on Mainactivity for passing Context:
Server.setActivityContext(getApplicationContext());
Code for Sever Class:
public class Server extends AsyncTask<Void, Void, Void> {
static Context mycontext;
public static void setActivityContext(Context receivingcontext) {
mycontext = receivingcontext;
}
Dialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = ProgressDialog.show(mycontext, "Updating ..", "Please wait......");
}
#Override
protected Void doInBackground(Void... params) {
//Background task
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
dialog.dismiss();
}
}
I am getting an error on progressdialog when calling this server class. Though context is passed, any fixes which you can suggest.
Error:
FATAL EXCEPTION: main
Process: jss.smartapp, PID: 22915 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
Don't use static methods. Use a proper constructor.
public class ServerTask extends AsyncTask<Void, Void, Void> {
private Context mycontext;
public ServerTask(Context c) {
this.mycontext = c;
}
Call it with
new ServerTask(MainActivity.this).execute();
You have method setActivityContext and send back activity context, not application context
You can create a constructor for passing the context like this
public class Server extends AsyncTask<Void, Void, Void> {
private static final String TAG = "Server";
private Context mContext;
public Server(Context context){
mContext = context;
}
Dialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "onPreExecute:called ");
dialog = ProgressDialog.show(mContext, "Updating ..", "Please
wait......");
}
#Override
protected Void doInBackground(Void... params) {
//Background task
Log.d(TAG, "doInBackground: called");
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d(TAG, "onPostExecute: called");
dialog.dismiss();
}
}
and call this Server class like this
new Server(MainActivity.class).execute();

Android: toast inside AsyncTask

I have an AsyncTask class SearchForQuestions that is called from an Activity QuizMap. When looping through an array in SearchForQuestions I can't find the correct context for toast to appear within the AsynTask.
The standard Toast.makeText(getApplicationContext(), "This is Toast!!!", Toast.LENGTH_SHORT).show(); gives error getApplicationContext() undefined.
I have tried some of the solutions to this offerred by SO, most of them are listed here and concern getting UiThread and running on that.
I can't get this to work however. Here's example code snippets of what i have tried. I have put a method in QuizMap and try calling it from SearchForQuestions but SearchForQuestions isn't recognised. How can I get around this? )Still a newbie at java...)
// QuizMap activity
public class QuizMap extends FragmentActivity
implements OnMarkerClickListener {
private GoogleMap map;
private static final String TAG = "QuizMap"; // debugging
...
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quizmap);
map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
...
}
// make toast inside AsyncTask
public void showNotNearToast(final String toast) {
QuizMap.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(QuizMap.this, "This is Toast!!!", Toast.LENGTH_SHORT).show();
}});
}
.
// SearchForQuestions class
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
// checks for proximity to question locations
Location location =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
#Override
protected DataHandler doInBackground(String... pointsList) {
String result = pointsList[0];
...
}
#Override
protected void onPostExecute(DataHandler result) {
ArrayList<String> resultsArray = result.results;
Integer numPoints = resultsArray.size();
for (int i =0;i<numPoints;i++){
String[] pointDetails = resultsArray.get(i).split("::");
...
// we can make use of the Android distanceTo function to calculate the distances
float distance = location.distanceTo(fixedLoc);
if (i > DIST) { // this is UCL
showNotNearToast("My Message"); // showNotNearToast undefined
if (distance < DIST) {
...
}
};
I'm going t close this question. I haven't solved my problem but the number of answers provided that apparently work in other situations suggest there's something else going on. I'm going to re-structure the classes to get around having to call from within AsyncTask.
Just Toast it, why do you want to create a function for it? onPostExecute() is already on UI thread.
You are not able to access because inner Class can not call functions of Outer class unless you pass instance of the outer class.
Call your toast in onPostExecute
Create an interface for a callback.
public interface ToastCallback {
public void invoke(String text);
}
Your AsyncTask constructor
private ToastCallback toastCallback;
public SearchQuestions(ToastCallback callback) {
this.toastCallback = callback;
}
// in doInBackground() {
toastCallback.invoke("Toast from background");
}
In Your Activity,
private void showNotNearToast(String text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
});
}
public class MyToastCallback implements ToastCallback {
#Override
public void invoke(String text) {
showNotNearToast(text);
}
}
// Asynctask call
new SearchQuestion(new MyTosatCallback()).execute(<Your params here>);
Try this from inside your AsyncTask:
myActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
Where you have your
showNotNearToast("My Message"); // showNotNearToast undefined
Replace myActivity with the name of your Activity.
(Ab)use the publishProgress method
private class ToastAsyncTask extends AsyncTask<Void, String, Void>{
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
Toast.makeText(getApplicationContext(), values[0], Toast.LENGTH_SHORT).show();
}
}
**UPDATE: ** since you are having problems with context for some reason, use this version. Tough the implementation above works for me.
private class ToastAsyncTask extends AsyncTask<Void, String, Void> {
private WeakReference<Context> contextRef;
public ToastAsyncTask(Context context) {
contextRef = new WeakReference<Context>(context);
}
#Override
protected Void doInBackground(Void... voids) {
SystemClock.sleep(1000);
publishProgress("Toast msg string");
SystemClock.sleep(1000);
return null;
}
#Override
protected void onProgressUpdate(String... values) {
if (contextRef.get() != null) {
Toast.makeText(contextRef.get(), values[0], Toast.LENGTH_SHORT).show();
} else {
// The context was destroyed.. check what you are doing
}
}
}
Use it like this
new ToastAsyncTask(MainActivity.this).execute();
Pass the activity into the AsyncTask. See below.
private class SearchForQuestions extends AsyncTask<String, Void, DataHandler> {
Activity activity;
public void SearchForQuestions(Activity activity){
this.activity = activity;
}
//... rest of the code
public class QuizMap extends FragmentActivity implements OnMarkerClickListener {
/*...*/
new SearchForQuestions(this).execute();
/*...*/
/*When calling the toast:*/
Toast.makeText(this.activity, "This is Toast!!!", Toast.LENGTH_SHORT).show();

How to present a progress screen before/while a long running operation starts?

I am well aware that blocking the UI is not a good idea in general but there are some scenarios where my app simply cannot do any other work until some long running operations (e.g. loading data from a server) are complete.
Assume the user clicks the "Load Data" button. To indicate that no UI interaction is possible until the data is loaded I would like to grey out the screen and show some kind of activity indicator. This is no problem at all, I simply overlay the screen with a new Fragment.
The question is: How can I present this overlay fragment?
public void onLoadDataClick() {
// grey out the screen by simple showing a new Fragment
showActivityIndicatorOverlay();
// Start the long running opeartion
doVeryMuchWork();
dismissActivityIndicatorOverlay();
}
public void showActivityIndicatorOverlay() {
FragmentTransaction ft = context.getSupportFragmentManager().beginTransaction();
ActivityIndicatorOverlayFragment overlayFragment = ActivityIndicatorOverlayFragment.newInstance("Loading Data");
overlayFragment.show(ft, "activityIndicator");
}
This does NOT work. The overlay does not show up. If I remove dismissActivityIndicatorOverlay() the overlay shows up after the long running operation completed. This is not too suprising: I assume that the showing the new fragment is handeled at the end of the current run-loop or at the start of the next loop. Of course the long running operation has to complete before the run-loop ends and thus the overlay is displayed too late...
The obvious solution is of course to run the operation in a background thread using an AsyncTask:
public void onLoadDataClick() {
LoadDataTask loadTask = new LoadDataTask();
loadTask.execute();
}
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
showActivityIndicatorOverlay();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
dismissActivityIndicatorOverlay();
}
}
I was surprised, that this solution doesn't work either. It behaves exactly like the first approach: The overlay does not appear. When onPostExecute() is removed the overlay appears after the operation is complete. the Why is that?
What is the correct solution to present such an activity indicator?
I'd suggest the use of a ProgessDialog.
Declare a ProgressDialog as an instance variable. Something like : ProgressDialog pDialog;
then inside onCreate() :
pDialog = new ProgressDialog(this);
//The next two methods will ensure that the user is unable to
//cancel the Progress Dialog unless you explicitly
//do so by calling `pDialog.dismiss();`
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);
Modify AsyncTask somewhat like this :
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
pDialog.setMessage("Loading Data.. Please Wait.");
pDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
pDialog.dismiss();
}
}
A ProgressDialog is very much the canonical solution for these cases...
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog mProgress;
#Override
protected void onPreExecute() {
mProgress = new ProgressDialog(context);
mProgress.setTitle("So much to do");
mProgress.setMessage("Doing very much work");
mProgress.setIndeterminate(true);
mProgress.setCancelable(false);
mProgress.show();
}
#Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
#Override
protected void onPostExecute() {
mProgress.dismiss();
}
}
As for your attempted solutions, the first one does not work for the very reasons you state. The second should, though.
You can do something like this, if you're not doing heavy stuff precisely on setContentView(R.layout.main)
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
handler = new Handler();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
//Do some heavy stuff
return null;
}
#Override
public void onPostExecute(Void result){
handler.post(new Runnable(){
#Override
public void run(){
setContentView(R.layout.main);
}
});
}
}.execute();
}
OR you can use progress dialog
private class LongTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog pd;
Context context;
public LongTask(Context c)
{
this.context = c;
}
#Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setTitle("Please wait...!");
pd.setMessage("Loding the information");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
}
#Override
protected Void doInBackground(Void... params) {
// do your heavy tasks here
}
#Override
protected void onPostExecute() {
if (pd.isShowing())
pd.dismiss();
}
}
Call AsyncTask like this
new LongTask(your_activity.this).execute();

ProgressDialog in AsyncTask only displayed at the end of the task for a short time

I have a AsyncTask<Client, Void, Boolean> called LoginTask with a ProgressDialog, which you can see here.
Now my problem is, if I launch this task with LoginTask(...).execute().get() the ProgressDialog is only shown very short at the end of the AsyncTask. Also I've put in some Thread.sleep(), but if I do that, I also get a ProgressDialog at the end of the Thread.
How can the ProgressDialog be displayed the whole async task?
public class LoginTask extends AsyncTask<Client, Void, Boolean>
{
private ProgressDialog progressDialog;
private MainActivity activity;
public LoginTask(MainActivity activity)
{
this.activity = activity;
}
#Override
protected void onPreExecute()
{
progressDialog = new ProgressDialog(activity);
progressDialog.setIndeterminate(true);
progressDialog.setMessage(activity.getText(R.string.asynctask_login_connect));
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected Boolean doInBackground(Client... params)
{
try
{
Client client = params[0];
if (client.connect())
{
progressDialog.setMessage(activity.getText(R.string.asynctask_login));
if (client.manageHandshake())
{
return true;
}
else
return false;
}
else
return false;
}
catch (Exception e)
{
Log.e(LoginTask.class.getSimpleName(), "Can not handshake and connect to/with server.", e);
return false;
}
}
#Override
protected void onPostExecute(Boolean result)
{
progressDialog.dismiss();
}
}
From the docs of the get(),
Waits if necessary for the computation to complete, and then retrieves
its result.
This means that it will block the calling Thread until the execution is done; this defeats the whole purpose of using AsyncTask. Just call execute() and update the UI Thread from onPostExecute()

ProgressBar not showing up during a AsyncTask

I am trying to make a simple task in background and show a progress bar while it is being done.
This is the code for the main (and the only) Activity:
public class Login extends Activity {
public static ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
(...)
// In some onClick Eevent..
JSONObject result = new Urltasks().execute(...).get();
(...)
}
}
This is the code for the activity:
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
protected void onPreExecute() {
System.out.println("Inicia onPreExecute");
Login.progressDialog.show();
}
protected void onPostExecute(String result) {
Login.progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
With this code the ProgressDialog shows up when the task ends, and it doesn't dismiss.
Problem is here:
JSONObject result = new Urltasks().execute(...).get();
Calling get() on an AsyncTask blocks the current thread, i.e. your UI thread, until the AsyncTask is executed. Therefore the progress dialog cannot run. Remove the get().
To obtain the result of the AsyncTask, you can e.g. pass in a listener callback to the asynctask that gets notified when the result is available:
class YourAsyncTask extends AsyncTask<ParamType, ProgressType, ResultType> {
private YourResultListener mListener;
interface YourResultListener {
void onResultAvailable(ResultType result);
}
YourAsyncTask(YourResultListener listener) {
mListener = listener;
}
#Override protected ResultType doInBackground(ParamType... params) {
//...
}
#Override protected void onPostExecute(ResultType result) {
mListener.onResultAvailable(result);
}
}
You can use it like:
mProgressDialog.show();
new YourAsyncTask(new YourResultListener() {
#Override void onResultAvailable(ResultType result) {
mProgressDialog.dismiss();
// use result
}).execute(params);
Personally I like to keep user interface elements such as progress dialogs decoupled from async tasks.
Don't put your progress dialog in your log in class. Keep it in the async task
this is how you show your dialog
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
Edited this for you:
class Urls extends AsyncTask<String, Integer, JSONObject>{
ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(yourActivityHERE.this, "",
"Loading... please wait.");
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Some work being done. I do not use Login.progressDialog here
}
}
create the constructor in your Urltasks sending the context of the calling class.
then use that context to create the progress dialog in the preExecute of your Urltasks
class Urltasks extends AsyncTask<String, Integer, JSONObject>{
Context mContext;
public static ProgressDialog progressDialog;
public UrlTasks(Context c){
mContext=c;
}
protected void onPreExecute() {
progressDialog = new ProgressDialog(mContext);
progressDialog.setMessage("Sending data...");
progressDialog.setCancelable(false);
progressDialog.show();
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
protected JSONObject doInBackground(String... arg0) {
// Do your work here
}
}

Categories

Resources