I'm writing an app that at many points will attempt to retrieve account information from a website. I'd like to write a single function ("getAccount()") to do the following:
Show a ProgressDialog
Make the call to the website
Wait for a response
Clear the ProgressDialog
Return control to the calling function after the first four steps are done
I'm not having a problem with getting the data from the page; the problem I have is with the whole "show dialog / wait for completion / return control to the calling function" portion. Either the ProgressDialog doesn't show at all, or the function returns to the caller immediately after making the data request from the site, without giving it enough time to retrieve the data.
Any help would be most appreciated.
EDIT: I'm adding a bit of code below for what I have with AsyncTask. Notice that I have the line MsgBox("done") inside grabURL(); this is simply a Toast call. When I run this code, "done" pops up while the HTTP request is still being made. This MsgBox line only exists so I can see if grabURL is properly waiting for GrabURL to finish (which it isn't).
public void grabURL() {
new GrabURL().execute();
MsgBox("done");
}
private class GrabURL extends AsyncTask<String, Void, Void> {
private ProgressDialog Dialog = new ProgressDialog(MyContext);
protected void onPreExecute() {
Dialog.setTitle("Retrieving Account");
Dialog.setMessage("We're retrieving your account information. Please wait...");
Dialog.show();
}
protected Void doInBackground(String... urls) {
try {
// Get account info from the website
String resp = GetPage(ThePage); // I have this classed out elsewhere
// Some other code that massages the data
AccountRetrievalSuccess = true;
} catch (Exception e) {
AccountRetrievalSuccess = false;
}
return null;
}
protected void onPostExecute(Void unused) {
Dialog.dismiss();
}
}
The message box done appears because AsyncTask is using a separate thread(s) to run doInBackground. The call to execute does NOT block. You could move message box done to onPostExecute following the call to dismiss. Tip. You may want to call progress.cancel in onPause or you may get unwanted behaviour on orientation change. Finally, if you are retrieving info in doInBackground, consider returning the info in doInBackground. The info will be passed to onPostExecute. So if the info is object MyInfo consider:
private class GrabURL extends AsyncTask<String, Void, MyInfo> {
Can't say for sure without seeing some code but sounds like you are making a asynchronous call to the website when you want to make a synchronous call (which will block and wait for return data) to the website instead.
You want to use an AsyncTask, generate a non-user-cancellable ProgressDialog in the onPreExecute, do your work in doInBackground, and dismiss it in onPostExecute.
Something like this:
public class MyApp extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// blah blah blah
URL url;
try
{
url = new URL("http://example.com");
new MyTask().execute(url);
}
catch (MalformedURLException e)
{
}
}
protected void doSomeStuff()
{
// stuff to do after the asynctask is done
}
protected void throwAWobbly()
{
// stuff to do if you didn't get the data
}
// inner class to do the data getting off the UI thread,
// so android doesn't "not responding" kill you
private class MyTask extends AsyncTask<URL, Void, Boolean>
{
private ProgressDialog dialog;
private boolean gotData = false;
protected void onPreExecute()
{
// create a progress dialog
dialog = ProgressDialog.show(MyApp.this, "",
"Doing stuff. Please wait...", false, false);
}
protected Boolean doInBackground(URL... urls)
{
// get your data in here!
return gotData;
}
protected void onPostExecute(Boolean result)
{
// get rid of the progress dialog
dialog.dismiss();
if (true == result)
{
// got all data!
doSomeStuff();
}
else
{
// oops!
throwAWobbly();
}
}
}
}
Related
In the Java code I have executed an AsyncTask class and with the returned result I have done a recursive call to itself in the onPostexecute method. Example:
MainActivity.java
public void button_clicked(){
UploadAsync send_data = new UploadAsync(MainActivity.this);
send_data.execute("send first data", user_data, file_path);
}
UploadAsync.java
#Override
protected String doInBackground(String... params) {
String task = params[0];
if(task.equals("send first data"){
String user_data = params[1];
String file_path = params[2];
//send in the user_data to a php file
}else if(task.equals("send file"){
String file_path = params[1];
//send the file_path to another php file
}
}
#Override
protected void onPreExecute() {
ProgressDialog pd = ProgressDialog.show(context, "Sending", "Please wait");
}
#Override
protected void onPostExecute(String result) {
if(result.equals("data sent"){
UploadAsync send_data = new UploadAsync(context);
send_data.execute("send file", file_path);
}else{
//show error
}
pd.dismiss();
}
The code above is only an example made. Now the thing is, implementing this example will run the progress dialog twice. I have tried many ways to only show the progress dialog once while the AsyncTask is sending the user data and the file path but I'm not succeeding. Is there any suggestions on how to implement this correctly?
Can't you call pd.dismiss() and dismiss ProgressDialog for the current UploadAsync before executing new UploadAsync?
In onPostExecute first, dismiss the dialog and then start new asynctask like this:
#Override
protected void onPostExecute(String result) {
pd.dismiss();
if(result.equals("data sent"){
UploadAsync send_data = new UploadAsync(context);
send_data.execute("send file", file_path);
}else{
//show error
}
}
I hope this will help you.
Let ProgressDialog as global data .
private ProgressDialog pd;
#Override
protected void onPreExecute() {
// show the ProgressDialog
if (pd == null) {
pd = ProgressDialog.show(context, "Sending", "Please wait");
}
}
#Override
protected void onPostExecute(String result) {
if (result.equals("data sent") {
UploadAsync send_data = new UploadAsync(context);
send_data.execute("send file", file_path);
}else{
//show error
}
// edited here ,make the ProgressDialog dismiss
if (pd.isShowing() && pd != null) {
pd.dismiss();
pd = null;
}
}
In that case use callback mechanism between the async task and the caller(here, MainActivity).
Implement as I explained below.
Define an interface with showProgressDiaglog() and
DismissProgressDialog() methods.
MainActivity implements this interface and implements the two
methods to show and dismiss progress dialog respectively.
Define setter method in your AsyncTask class and call this setter
method from the MainActivity by passing this(this refers to
MainActivity) after creating the AsyncTask instance and before
calling execute method. store the passed interface implementation in
the AsyncTask class as an instance variable.
Modify AsyncTask constructor to pass the task type instead of passing
in the execute method and store this task type in the AsyncTask as an
instance variable.
Now from within the AsyncTask constructor, in onPreExecute()
method, call showProgressDialog() method based on the task type.
and in onPostEecute() method call dismissProgressDialog()
depending on the task type.
I'm using sockets in my app. I created a class SocketClient with methods: onConnect, onSendData, onReadData. Method onReadData extends AsyncTask. It waits for a string message from the server inside doInBackground and then makes a new task to listen for the incoming message. Now I want to pause the UI in my MainActivity class while the message is loading and get it, but don't know how to do that. My Async Task looks like:
public void ReadMyData() {
mt = new ReadDataAsync();
mt.execute();
}
class ReadDataAsync extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// a lot of work
return message;
}
#Override
protected void onPostExecute(String result) {
ReadMyData();
}
}
and MainActivity:
public SocketClient mySocketClient = new SocketClient();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mySocketClient.onConnect();
//there I need wait message load and take it
setContentView(R.layout.activity_game);
WorkWithMessage(message);}
Create a progress DIALOG and start it when you know the message is loading, than take it off when the message is loaded.
You can create a progress DIALOG like this:
ProgressDialog pd = New ProgressDialog();
pd.setTitle(”title”);
pd.setMessage(”messgae”);
pd.setCancleable(false);
Than call
pd.show();
When you wish to load the message, and
pd.dismiss();
When you’r done.
I am developing an Android app which has 2 classes. Game, which extends Activity, and GameView, which extends View.
When the game is loaded, it sets the content view to GameView, which is just a drawing class that uses a canvas to display the game.
I am trying to create a ProgressDialog in the Game class which will show a spinner after a certain action has been done, as this takes a long time to complete. So far I have the following:
setContentView(R.layout.activity_game);
ProgressDialog pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("Calculating hint");
pd.show();
AsyncTask<String[][], Void, SudokuSquare> nextSquareThread = new GetNextSquare().execute(puzzleNumbers);
next = nextSquareThread.get();
pd.dismiss();
setContentView(gameView);
And my AsyncTask class looks like this:
private class GetNextSquare extends AsyncTask<String[][], Void, SudokuSquare> {
private ProgressDialog dialog = new ProgressDialog(Game.this);
#Override
protected void onPreExecute() {
this.dialog.setMessage("Finding next number");
this.dialog.show();
}
#Override
protected SudokuSquare doInBackground(final String[][]... args) {
try {
SudokuAdvancedSolver solver = new SudokuSolver(args[0]);
return solver.getOneValue();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
protected void onPostExecute(final SudokuSquare result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
At the moment I have two ProgressDialogs, one inside the AsyncTask and one outside. Which one is correct? Also, the spinner is not being displayed at all. What am I overlooking which is causing this to be the case?
only the one outside is correct. because you are trying the main thread (the UI thread of your activity) by another thread (your asychronic task). you should use a handler in place of this :
1/ you show the progress bar
2/ you load the game in a thread
3/ when the game is loaded you send a message to the handler which will stop the progress bar.
See this exemple . you should dismiss your dialog in the handler (when the handler receives the message from the thread) .
If you don't implement a listener on Asynctask, i could suggest you to dismiss your progress dialog onPostExecute
private ProgressDialog dialog;
public void setProgressDialog(ProgressDialog dialog){
this.dialog = dialog;
}
#Override
protected void onPostExecute(final SudokuSquare result) {
dialog.dismiss();
}
and before you executing Asynctask add this code
nextSquareThread.setProgressDialog(pd);
How do i make sure that the async tasks finishes before i run certain tasks. I need to use a variable AFTER the async tasks changes the value of that variable. If i run the code before async is done running then im screwed. any help? im obviously new to async tasks. If you look at my code im probably not using onPostExecute() as it was intended so advice would be helpful. My initial thought was to keep adding things to the async task but im thinking that this is just bad practice since i have tons of things that must be run in series. Basically, what i think it boils down to is: how do i make sure that the tasks in the UI thread dont start to run before my async task has finished.
public class MainActivity extends MapActivity {
myJSONmap;
public void onCreate(Bundle savedInstanceState) {
new AsyncStuff().execute();
locatePlace(myJSONmap);
class AsyncStuff extends AsyncTask<Void, Integer, JSONObject> {
#Override
protected JSONObject doInBackground(Void... params) {
jObject = GooglePlacesStuff.getTheJSON(formatedURL);
return null;
}
#Override
protected void onPostExecute(JSONObject result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
myJSONmap = JSONextractor.getJSONHMArrayL(jObject); // getting the parsed data from the JSON object.
//the arraylist contains a hashmap of all the relevant data from the google website.
}
}
You probably want to read more about AsyncTask on Android Developer
http://developer.android.com/intl/es/reference/android/os/AsyncTask.html
About tips, my personal choice is to pass a Boolean to onPostExecute. That way you can evaluate if the doInBackground was succesful, an then figure out what to do (Error message or update the layout).
Keep in mind that in onPostExecute method ideally should only make the screen update, assuming you have the data ok. In your example, why not include the
myJSONmap = JSONextractor.getJSONHMArrayL(jObject);
on the doInBackground? And then call
locatePlace(myJSONmap);
Like this:
class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
String errorMsg;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... v) {
try{
jObject = GooglePlacesStuff.getTheJSON(formatedURL);
myJSONmap = JSONextractor.getJSONHMArrayL(jObject);
//do stuff
return true;
} catch (JSONException e){
errorMsg="Something wrong in the json";
return false;
}
}
#Override
protected void onPostExecute(Boolean success) {
if(success){
locatePlace(myJSONmap);
//update layout
} else {
//show error
}
}
}
You can ue below code to execute async task -
MyAsyncTask_a asyncTask_a = new MyAsyncTask_a();
asyncTask_a.execute();
Once doInBackground() task is finished then only control will go to postExecute().
You can't perform any UI operations in doInBackground , but you can do so in preExecute() and postExecute().
class MyAsyncTask_a extends AsyncTask<Void, Void, Integer> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Integer doInBackground(Void... arg0) {
// TODO Auto-generated method stub
return 1;
}
#Override
protected void onPostExecute(Integer result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
Hope this will help you.
I am working on Android AsyncTask, I wish to make a progress bar during my program is loading. Here's how I make it.
A class is declared here...
private ArrayList<String> result1 = new ArrayList<String>(); //class variable
onCreate()
{
Some stuff here...
new ATask().execute();
for (int i = 0; i <result1.size();i++)
{
output = output +result1.get(i) + "\n\n";
}
textView.setText(output);
}
private void do0()
{
ArrayList<Sentence> result = new ArrayList<Sentence>();
ArrayList<String> result2 = new ArrayList<String>();
result = do1("link", true); //just some function I am working
result1 = do2(result,10);//do2 return ArrayList<String>
}
private class ATask extends AsyncTask<String, Void, String>{
private ProgressDialog progress = null;
#Override
protected String doInBackground(String... params) {
do0();
return null;
}
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected void onPostExecute(String result) {
progress.dismiss();
//adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
progress = new ProgressDialog(ReadWebPage.this);
progress.setMessage("Doing...");
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.show();
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
};
My intention is that, while the progress bar is loading, it will finish the do0() and modify result1, then my oncreate can use that result1 to display in it's TextView. However my TextView is always empty in this setting. So I move the
for (int i = 0; i <result1.size();i++)
{
output = output +result1.get(i) + "\n\n";
}
textView.setText(output);
into the do0() (right after the result1 = do2()), but then the program will crash. I am not familiar with these thread settings, thanks for your help in advance.
You'll be better served with a thread that holds a Handler object that was initialized on the main thread. Using the handler, you can post() little snippets to be executed on a main thread - like update a progress bar. You can do the same Handler trick from the AsyncTask, but IMHO threads are cleaner.
Said snippets should be implemented as Runnables. Feel free to use a nested anonymous class one-liner.
The problem is with the design of your code. AsyncTask happens asynchronously, so as soon as you call execute on your AsyncTask the rest of your onCreate will execute immediately. AsyncTask will essentially run on a new thread and execute in parallel with your Activity.
What I think you want is to set your TextView in the onPostExecute method of your AsyncTask. onPostExecute gets called after doInBackground is finished.
Also, it is important to keep in mind that doInBackground happens on a background thread, so you cannot make changes to your Activity's UI from code within it. onPre/PostExecute run on the UI thread, so you can make UI changes there, but any code within those methods will also block the UI.