in this app, the user logs in and their credentials are checked against a server.
The user could be waiting a few seconds, depending on how fast the phone can open a data connection if at all. I need dialog box saying "please wait" or "verifying credentials" or something a long those lines after the user clicks log in.
Desired visual order: press log in -> "please wait" dialog is show in this same activity -> when result comes in from server a new activity is loaded (or error is thrown)
Current visual order: press log in -> user waits as if the app is frozen -> new activity is loaded
I'm trying to do this threading thing with AsyncTask but I'm just not getting it right now!
class Progressor extends AsyncTask<Void, Void, Void> {
ProgressDialog dialog;
protected void onPreExecute(){
dialog = ProgressDialog.show(Login.this, "Logging In",
"Verifying Credentials, Please wait...", true);
}
Then in my oncreate method I had all of the other logic like user clicking the button and stuff, but I've since moved that into the AsyncTask method's doInBackGround function
/* When the Login Button is clicked: */
Button loginButton = (Button) findViewById(R.id.loginButton);
loginButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Progressor showMe = new Progressor();
showMe.onPreExecute();
showMe.doInBackground(null);
showMe.onPostExecute();
and onPostExecute simply dismisses the dialog box
Why doesn't this work and how should it be re-arranged. What variable should I be passing into the showMe.doInBackGround() function, it is void. In debugging it never goes in here
#Override
protected Void doInBackground(Void... arg0) {
Don't call the onPreExecute/doInBackground methods of an AsyncTask manually; just call execute() on it and it will call all your methods in the proper places from the correct threads. It defeats the entire purpose of an asynchronous task to call all of its methods synchronously from the UI thread (which is what your sample code does).
That isn't how you use an AsyncTask, have a look at the documentation. Once you have created a new instance of your task, just call execute(), not the individual methods:
Progressor showMe = new Progressor();
showMe.execute();
I have a similar code at the start of my application i load the current settings from the server, it works for me with:
public static ProgressDialog verlauf;
public static String vmessage = "";
static Handler handler = new Handler();;
public static void initialize_system(final Context ctx)
{
verlauf = ProgressDialog.show(ctx, "Starte FISforAndroid..", "synchronisiere Einstellungen",true,false);
new Thread(){
#Override
public void run(){
Looper.prepare();
GlobalVars.table_def.initialize();
vmessage = "erstelle Tabellen";
handler.post(verlauf_message);
builded = sqldriver.create_tables();
vmessage = "setze Systemkonstanten";
handler.post(verlauf_message);
builded = setsystemvars(ctx);
vmessage = "synchronisiere Einstellungen";
handler.post(verlauf_message);
builded = settings.sync_ini();
builded = settings.set_ini();
GlobalVars.system_initialized = builded;
switch(GlobalVars.init_flags.FLAG){
case 0:
break;
case GlobalVars.init_flags.UPDATE:
//load the update
break;
}
verlauf.dismiss();
}
}.start();
}
You need to call showMe.execute(), rather than directly calling doInBackground or onPreExecute etc.
Related
I've got a main Activity, an extra class for my fragment, and inside this fragment is an AsyncTask, which gathers data from various android library (Wifi SSID, BSSID, etc). When I start my app the app shows a blank screen, without any UI. Then after about 2 seconds, the whole data is being shown. I actually want to display my TextViews as "Not connected to a wifi network" in the background, while showing a ProgressDialog until the data is being displayed. I've got the ProgressDialog in my MainActivity, and calling it in my AsyncTask onProgressUpdate
MainActivity.progressDialog = ProgressDialog.show(MainActivity.c,
"ProgressDialog Title",
"ProgressDialog Body");
I'm updating my TextViews in the doInBackground methode (via another methode outside the Fragment)
((Activity) getActivity()).runOnUiThread(new Runnable() {
Would be too big a comment so i'll just put it here.
Sounds like you are using both fragment and AsyncTask in an incorrect way. You should never do anything UI relevant in doInBackground.
Here is an example of what you could do.
I assume the following scenario:
You have a main activity
You have a fragment containing TextViews
You wish to populate the TextViews after loading some data using AsyncTask with a progressDialog
The approach would be to:
Add the fragment in onCreate of your activity (if the fragment is not defined in the layout, then it will automatically be added).
Create the AsyncTask in your fragment like this:
private class LoadData extends AsyncTask<Void, Void, List<String>> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
// getActivity() is available in fragments and returns the activity to which it is attached
progressDialog= new ProgressDialog(getActivity());
progressDialog.setTitle("ProgressDialog Title");
progressDialog.setMessage("ProgressDialog Body");
progressDialog.setIndeterminate(true)
progressDialog.setCancelable(false)
progressDialog.show();
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
List<String> results = new ArrayList<String>();
//do loading operation here
//add each of the texts you want to show in results
return results;
}
// onPostExecute runs on UI thread
#Override
protected void onPostExecute(List<String> results )
{
progressDialog.dismiss();
// iterate results and add the text to your TextViews
super.onPostExecute(result);
};
}
Start the AsyncTask in onCreate of your fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
new LoadData().execute();
super.onCreate(savedInstanceState);
}
This way you avoid calling directly back to your activity, which really should not be necessary in your scenario (unless I have misunderstood).
Otherwise please post all the relevant code and layouts.
This line:
I'm updating my TextViews in the doInBackground methode
points to your problem. You need to use the AsyncTask method onProgressUpdate() to publish to the UI thread. You do not call onProgressUpdate() directly, instead you call publishProgress().
Interestingly, I answered a similar question yesterday here: android AsyncTask in foreach
and it includes an example.
Here's what you need to do.
(1) From the place you run the code that gathers data, you should first display the progress dialog. Something like this:
busy = new ProgressDialog (this);
busy.setMessage (getString (R.string.busy));
busy.setIndeterminate (true);
busy.setCancelable (false);
busy.show();
(2) Then you start your data gathering. This must be done in a separate thread (or Runnable). Do something like this:
Thread thread = new Thread ()
{
#Override
public void run()
{
try
{
... gather data ...
Message msg = handler.obtainMessage();
msg.what = LOADING_COMPLETE;
msg.obj = null;
handler.sendMessage (msg);
}
catch (Exception e)
{
Message msg = handler.obtainMessage();
msg.what = LOADING_FAILED;
msg.obj = e.getMessage(); // maybe pass this along to show to the user
handler.sendMessage (msg);
}
// get rid of the progress dialog
busy.dismiss();
busy = null;
}
}
(3) Add a handler to the activity to receive notification when data gathering is complete:
Handler handler = new Handler()
{
#Override
public void handleMessage (Message msg)
{
if (msg.what == LOADING_COMPLETE)
loadingComplete ();
else if (msg.what == LOADING_FAILED)
loadingFailed ((String)msg.obj);
}
};
(4) Implement the handlers:
private void loadingComplete ()
{
...
}
private void loadingFailed (String errorMessage)
{
...
}
That's the essentials.
I have an AsyncTask which does a lot of JSON calculations.
public class InitializationTask extends AsyncTask<Void, Void, InitializationResult> {
private ProcessController processController = new ProcessController();
private ProgressDialog progressDialog;
private MainActivity mainActivity;
public InitializationTask(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(mainActivity);
progressDialog.setMessage("Die Daten werden aufbereitet.\nBitte warten...");
progressDialog.setIndeterminate(true); //means that the "loading amount" is not measured.
progressDialog.setCancelable(false);
progressDialog.show();
};
#Override
protected InitializationResult doInBackground(Void... params) {
return processController.initializeData();
}
#Override
protected void onPostExecute(InitializationResult result) {
super.onPostExecute(result);
progressDialog.dismiss();
if (result.isValid()) {
mainActivity.finalizeSetup();
}
else {
AlertDialog.Builder dialog = new AlertDialog.Builder(mainActivity);
dialog.setTitle("Initialisierungsfehler");
dialog.setMessage(result.getReason());
dialog.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
mainActivity.finish();
}
});
dialog.show();
}
}
}
processController.initializeData() runs for about 20 seconds. All this works. It even works when I install the application, and pressing home button while application is initializing. The AsyncTask is working in the background. When I restart the application from Android device again after the AsyncTask has been finished, the application still works.
But the application cannot handle this use case: When I deploy the application (or start it when no data is initialized), so that it really takes about 20sec to initialize the data and when I hit home to close the application while initialization (the AsyncTask) runs in the background and start the application again, it leads to unexpected behavior as RuntimExceptions and so on. It seems that the device wants to load the application twice, but none of them can start successfully. How to deal with that?
I thought about checking if there is a running AsyncTask in MainActivity to avoid starting it again:
private InitializationTask initializationTask = new InitializationTask(this);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (!AsyncTask.Status.RUNNING.equals(initializationTask.getStatus())) {
initializationTask.execute((Void[])null);
}
initializeMap();
}
Unfortunately this does do nothing. Moreover I'm not sure if such use case is possible at all, because when I start the same application twice, they cannot "share" an AsyncTask. Should I somehow avoid starting the application twice or something? I'm not sure what options do I have on this? Any ideas?
I usually do it a bit more bluntly. I set my AsyncTask reference to null when I'm not using it. When the onClick fires, I check if it's not null, which means I started it. If it is null, I create and execute a new AsyncTask right there. It is plenty fast and it's clean enough. One bonus of this approach is that an AsyncTask can only be executed once anyway, so it fits in well with that. At the end of onPostExecute, you can set the reference back to null again if you intend to stay in the same Activity.
While you're perfecting your AsyncTask flow, make sure that it survives orientation changes as well.
I found the solution: It's actually not an AsyncTask issue. The problem was that my parse method of JSONParser (that does the most of the work) which is invoked in processController.initializeData(), was not synchronized.
In my activity class i want to perform a series of long calculations that require around 5 sec to complete when i press a button. So in order to do that i have create a new class which does all the calculations in its run method(since it implements Runnable) and when finished i set a variable to true to indicate that. In the code that checks the if the button is pressed i start a new Thread passing my class in it and then cheking whether the run method has finished or not. If it finished i then print the data. The problem with this is that when i check if the calculations have finished they actually havent so it pass that line of code and never prints the data. I have tried to do the Async Class method but still i think it wont work. Is there a way to create the thread when i press the button and keep checking if had finished so i can print the data? Which piece of code in an Activity is actually get executed over and over again? Thanks for any information.
if(v.equals(this.button)) {
EditText param1 = (EditText)findViewById(R.id.param1);
EditText param2 = (EditText)findViewById(R.id.param2);
calculations = new MathCalc(param1.getText().toString(), param2.getText().toString());
new Thread(calculations).start();
while(!calculations.isReady());
Intent intent = new Intent(this,Show.class);
intent.putExtra("show1", calculations.getResult());
startActivity(intent);
}
This is want i want to achieve.
The AsyncTask is the right tool for this. The typical use case for the AsyncTask is that you want to do something small in the background and leave feedback through the UI before, during and/or after the task is done.
Be aware that running things in the background can get you in trouble if the user quits and restarts your activity a lot, since the background task will not end when the Activity is removed from screen.
An example activity is shown below. You could add the onPreExecute and onProgress methods to the AsynchTask to give the user feedback before and during the calculation.
public class CalcActivity extends Activity {
private Button button;
private TextView resultView;
public void onCreate() {
button = (Button) findViewById(R.id.my_button);
resultView = (TextView) findViewById(R.id.result);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
button.setEnabled(false);
AsyncCalculation calc = new AsyncCalculation();
calc.execute();
}
});
}
public class AsyncCalculation extends AsyncTask<Void, Void, Integer> {
#Override
protected Integer doInBackground(Void... params) {
int result = 0;
// Do some calculation
return result;
}
#Override
protected void onPostExecute(Integer result) {
// Set the result, start another activity or do something else
resultView.setText("The result was " + result);
button.setEnabled(true);
}
}
}
I don't see how this won't work with AsyncTask. You basically need to override two methods - doInBackground() and onPostExecute().
You're guaranteed that onPostExecute() will be invoked on the UI thread after the background computation finishes. You also don't have to worry how to update the UI Thread from another thread.
Here's a good example.
Use
Button someButton = (Button) findViewById(R.id.favouriteButton);
someButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while(!isDone){
doAlotOfCalculations();
}
}
});
thread.start();
}
});
private void doAlotOfCalculations(){
...
if(whenDone){
isDone = true;
}
....
}
Which piece of code in an Activity is actually get executed over and
over again?
There is no such a thing.
It is just onResume which executes every time you start(restart) this activity
My question is regarding ProgressDialog with Threads for my project. Basically what I want to do in this:
1) when a user clicks a login button the Activity sends an auth request to the server
2) while this is being done a ProgressDialog is shown
3) when the reponse comes I want to dismiss the ProgressDialog and go to the next home page if the login successful and if not than display the invalid login message kind of thing
how can i do ?? please share the code if you can
Thanks in advance
You need to do following thing :
In your Activity1
Override onClickListener of button, and call AsyncTask
yourButton.setOnClickListener( new onClickListener(){
//Call asynctask
YourAsyncTask yastask=new YourAsyncTask();
yastask.execute();
});
YourAsyncTask must be like this :
private class LoginOperation extends AsyncTask<String, Void, String> {
boolean isAuthorized;
//for showing background process is running use progress dialog
private ProgressDialog Dialog = new ProgressDialog(ClassName.this);
#Override
protected String doInBackground(String... params) {
//Here you have to consume your web service,
//Send username and password as parameter to your .net service and depending upon authorization process, you will send results
//for example if user is authorzed, you send some boolean type as result. or say simply username if he/she is an authorized user.
isAuthorized=Result;
return null;
}
#Override
protected void onPostExecute(String result) {
// execution of result of Long time consuming operation
try
{
if(Dialog.isShowing())
{
Dialog.dismiss();
}
}
catch(Exception e)
{
}
if(isAuthorized)
//Start Other Activity
else
//Display error message using Toast.
}
#Override
protected void onPreExecute() {
Dialog.setMessage("Authenticating.....");
Dialog.show();
// Things to be done before execution of long running operation. For example showing ProgessDialog
}
}
I'm trying to create a ProgressDialog for an Android-App (just a simple one showing the user that stuff is happening, no buttons or anything) but I can't get it right. I've been through forums and tutorials as well as the Sample-Code that comes with the SDK, but to no avail.
This is what I got:
btnSubmit.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
(...)
ProgressDialog pd = new ProgressDialog(MyApp.this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("Working...");
pd.setIndeterminate(true);
pd.setCancelable(false);
// now fetch the results
(...long time calculations here...)
// remove progress dialog
pd.dismiss();
I've also tried adding pd.show(); and messed around with the parameter in new ProgressDialog resulting in nothing at all (except errors that the chosen parameter won't work), meaning: the ProgressDialog won't ever show up. The app just keeps running as if I never added the dialog.
I don't know if I'm creating the dialog at the right place, I moved it around a bit but that, too, didnt't help. Maybe I'm in the wrong context? The above code is inside private ViewGroup _createInputForm() in MyApp.
Any hint is appreciated,
you have to call pd.show before the long calculation starts and then the calculation has to run in a separate thread. A soon as this thread is finished, you have to call pd.dismiss() to close the prgoress dialog.
here you can see an example:
the progressdialog is created and displayed and a thread is called to run a heavy calculation:
#Override
public void onClick(View v) {
pd = ProgressDialog.show(lexs, "Search", "Searching...", true, false);
Search search = new Search( ... );
SearchThread searchThread = new SearchThread(search);
searchThread.start();
}
and here the thread:
private class SearchThread extends Thread {
private Search search;
public SearchThread(Search search) {
this.search = search;
}
#Override
public void run() {
search.search();
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
displaySearchResults(search);
pd.dismiss();
}
};
}
I am giving you a solution for it,
try this...
First define the Progress Dialog in the Activity before onCreate() method
private ProgressDialog progressDialog;
Now in the onCreate method you might have the Any button click on which you will change the Activity on any action. Just set the Progress Bar there.
progressDialog = ProgressDialog.show(FoodDriveModule.this, "", "Loading...");
Now use thread to handle the Progress Bar to Display and hide
new Thread()
{
public void run()
{
try
{
sleep(1500);
// do the background process or any work that takes time to see progress dialog
}
catch (Exception e)
{
Log.e("tag",e.getMessage());
}
// dismiss the progress dialog
progressDialog.dismiss();
}
}.start();
That is all!
Progress Dialog doesn't show because you have to use a separated thread. The best practices in Android is to use AsyncTask ( highly recommended ).
See also this answer.
This is also possible by using AsyncTask. This class creates a thread for you. You should subclass it and fill in the doInBackground(...) method.