I've created an asynctask in my MapActivity, here it is:
class ReadLocations extends AsyncTask<String, String, String> {
GeoPoint apoint1;
GeoPoint apoint2;
ArrayList<GeoPoint> Locations = new ArrayList<GeoPoint>();
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MyMapLocationActivity.this);
pDialog.setMessage("DONE");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
protected String doInBackground(String... args) {
return null;
}
protected void onPostExecute() {
// dismiss the dialog once done
pDialog.dismiss();
}
}
I'm trying to execute it this way:
public class MyMapLocationActivity extends MapActivity {
private MapView mapView;
private ProgressDialog pDialog;
private ProgressDialog eDialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ReadLocations Read = new ReadLocations();
Read.execute();
...
My controlling dialog never disappears - it seems like my onPostExecute method is not called - why is that?
Becoz, your AsyncTask's onPostExecute() have not argument. which is return by doInBackground() .
SO override correctly both methods.
Something like,
#Override
protected String doInBackground(String... args) { // Return type of same as argument of onPostExecute()
return null;
}
#Override
protected void onPostExecute(String result) { // Add String argument in onPostExecute()
// dismiss the dialog once done
pDialog.dismiss();
}
As possible of execution of doInBackground() is fast because there is no any other work implementation in it. only one return statement..
You have not correctly overridden onPostExecute, the result parameter is missing
It should be something like
#Override
protected void onPostExecute(String result) {
// dismiss the dialog once done
pDialog.dismiss();
}
in Eclipse the best and the easiest way to override or implement methods of super classes correctly is:
Focus cursor on your AsyncTask body. Then mouse right click--> source --> override/implement methods.
Choose necessary methods.
Click OK. Methods will automatically add into your class.
Also you can generate constructors, getters/setters etc this way .
Related
Hi I'm making Login page that access MySQL database. But my Activity always runs the code that check fail/success before it finishes the AsyncTask.
I tried using asynctask.get() method, but it just freeze my UI and doesn't work.
I tried this answer that said I should call the result-checker method inside onPostExecute().
But since I need to change the TextView to show success/failed, it results in NullPointerException because I instantiate the TextView inside onCreate().
I can't move the TextView instantiation into constructor because it will return NullPointerException unable to instantiate activity ComponentInfo.
Login.java
public class Login extends Activity{
//declare global Views here
protected void onCreate(Bundle bundle){
//Setup views
}
protected void onClick(View v){
//Setup necessary variables
AsyncClass async = new AsyncClass(this);
async.execute(username, password);
}
public void checkSuccess(boolean success){
if(success)
textView1.setText("Success");
else
textView1.setText("Failed");
}
}
AsyncClass.java
public class AsyncClass extends AsyncTask<String, String, JSONObject>{
protected JSONObject doInBackground(String... params){
//access database
}
protected void onPostExecute(JSONObject json){
//read the json result
Login login = new Login();
login.checkSuccess(true);
}
}
Any solution? Thanks
How about making AsyncTask as your inner class?
So your code should look something like below.
public class Login extends Activity {
//declare global Views here
protected void onCreate(Bundle bundle) {
//Setup views
}
protected void onClick(View v) {
new AsyncClass().execute(username, password);
}
public void checkSuccess(boolean success) {
if (success) textView1.setText("Success");
else textView1.setText("Failed");
}
class AsyncClass extends AsyncTask < String, String, JSONObject > {
protected JSONObject doInBackground(String...params) {
//access database
}
protected void onPostExecute(JSONObject json) {
checkSuccess(true / false);
}
}
}
try this
protected void onPostExecute(JSONObject json){
//read the json result
Login login = (Login)context; // object that you pass to task constructor
login.checkSuccess(true);
}
Also you can add progress dialog to your task to indicate some job execution
public class BaseTask<T> extends AsyncTask<Object, Void, T> {
public Context context;
public ProgressDialog dialog;
public BaseTask(Context context) {
this.context = context;
this.dialog = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
this.dialog.setMessage(context.getResources().getString(R.string.loading));
this.dialog.show();
}
#Override
protected T doInBackground(Object... objects) {
//....
return something;
}
#Override
protected void onPostExecute(T result) {
if (dialog != null && dialog.isShowing())
dialog.dismiss();
// do something
}
}
You cannot edit the UI from the async task thread. In order to make updates to the UI thread, use the onProgressUpdate() method. This method is part of your AsyncTask class, is actually executed in the main UI Thread (I hope you use the async task as a nested class btw, since it is declared public I guess your not. You should change that). The onProgressUpdate() Method is called by the OS itself if you call publishProgress(...) inside your Async task.
A small sample:
protected JSONObject doInBackground(String... params){
publishProgress("test");
}
/**
* This method is part of the Async Task
*/
protected void onProgressUpdate(String... progress) {
login.checkSuccess(true);
}
I would use it this way, just override your onPostExecute where you need it or create a own interface
//create a object f your asyncclass and
//override the onPostExecute where you need it
mInfo = new ASYNCCLASS({
#Override
public void onPostExecute(Object result){
//doSomething something with your views!
}
}).execute();
Waiting is not the answer, because you do not know how long your Asynctask will take to end.
Code above is not tested, just pseudoce, but it should show what i mean.
Do not have my IDE round here, so if anybody would correct the brackets if neccessary would be great!
Greetz
In one of my app, I have a scenario where I need to do some background task. For doing that I am using Async Task. Also I am using custom progress dialog. Below is the layout of the custom progress dialog
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal"
android:orientation="vertical" >
<ProgressBar
android:layout_width="60dp"
android:layout_height="60dp"
android:indeterminateDrawable="#drawable/progressloader"
android:layout_gravity="center"/>
<TextView
android:id="#+id/progressMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black"
android:textSize="18sp"
android:text="Please wait...." />
</LinearLayout>
Everything works fine but when I try to set text to TextView then I am getting java NullPointerException.
AsyncTask code
private class InitialSetup extends AsyncTask<String, Integer, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
}
#Override
protected Long doInBackground(String... urls) {
// txtView.setText("Testing"); here I am getting the error
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
}
MainActivity
public class SummaryActivity extends Activity {
final TextView txtView = (TextView)findbyid(R.id.progressMessage);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accountsummary);
new InitialSetup().execute("");
}
}
If I understand correctly, your TextView of which you want to set the text can be found in the xml file progressbar.xml (i.e. R.layout.progressbar). This TextView can be obtained once the content view has been set (using setContentView()). In your code you set it before this call is been and the code of mussharapp, he is calling it to early. Namely, he calls it after the setContentView(R.layout.accountsummary) call which does not contain the TextView. Consequently, the variable txtView will be NULL and you will get a NullPointerException.
What you should do is the following:
Set the variable txtView in onPreExecute, after setContentView is called.
Based on Paresh Mayani's explanation: Use the runOnUiThread method.
For the code look down below:
private class InitialSetup extends AsyncTask<String, Integer, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
// The variable is moved here, we only need it here while displaying the
// progress dialog.
TextView txtView;
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
// Set the variable txtView here, after setContentView on the dialog
// has been called! use dialog.findViewById().
txtView = dialog.findViewById(R.id.progressMessage);
}
#Override
protected Long doInBackground(String... urls) {
// Already suggested by Paresh Mayani:
// Use the runOnUiThread method.
// See his explanation.
runOnUiThread(new Runnable() {
#Override
public void run() {
txtView.setText("Testing");
}
});
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
}
Yes, because you are trying to set the TextView inside the doInBackground() method, and this is not allowed,
Why not allowed? Because There is a only one Thread running which is UI Main Thread, and it doesn't allowed to update UI from thread process. read more info here: Painless Threading
So there is a solution if you want to set the TextView inside the doInBackground() method, do the UI updating operations inside the runOnUiThread method.
Otherwise, suggestion is to do all the UI display/update related operations inside the onPostExecute() method instead of doInBackground() method of your AsyncTask class.
(TextView)findViewByid(R.id.progressMessage);
should only be executed after the command setContentView().
TextView txtView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accountsummary);
**txtView = (TextView)findbyid(R.id.progressMessage);**
new InitialSetup().execute("");
}
Also you can only change UI elements in the main UI thread. doInBackground() is not in the main UI thread. Make UI changes in onPostExecute
public class InitialSetup extends AsyncTask<String, Integer, Long> {
private Activity activity;
ProgressDialog progressDialog;
public InitialSetup(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage("Starting task....");
progressDialog.show();
}
#Override
protected Long doInBackground(String... urls) {
// do something
//
return 0;
}
#Override
protected void onPostExecute(Long result) {
progressDialog.dismiss();
//Perform all UI changes here
**textView.setText("Text#2");**
}
}
The explanations are correct: You are not to make UI changes in any thread except the thread which create the UI. But AsyncTask has a method called
onProgressUpdate()
which always will run in the UI Thread. So based on the modifications by dennisg your code should look like this:
private class InitialSetup extends AsyncTask<String, String, Long> {
ProgressDialog dialog = new ProgressDialog(getParent(),R.style.progressdialog);
// The variable is moved here, we only need it here while displaying the
// progress dialog.
TextView txtView;
#Override
protected void onPreExecute() {
dialog.show();
dialog.setContentView(R.layout.progressbar);
// Set the variable txtView here, after setContentView on the dialog
// has been called! use dialog.findViewById().
txtView = dialog.findViewById(R.id.progressMessage);
}
#Override
protected Long doInBackground(String... urls) {
publishProgress("Testing");
fetchDetails();
return 0;
}
#Override
protected void onPostExecute(Long result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
populateUI(getApplicationContext());
}
#Override
protected void onProgressUpdate(String... update) {
if (update.length > 0)
txtView.setText(update[0]);
}
}
Note that the type of the parameter of onProgressUpdate is the second type given in AsyncTask!
Extra: To make your code more robust you should check if the progress dialog still exists before setting the text.
I have this code for managing some countrys on my database;
class checkCountryAsync extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
setContentView(R.layout.main);
}
#Override
protected String doInBackground(String... aurl) {
MDPIActivity.this.runOnUiThread(new Runnable() {
public void run() {
CountryTable country = new CountryTable() ;
country.EnterCountry();
}
});
return null;
}
}
With this, I would like to set the content View and then in background, that the method onBackground works, but I have still to wait for the content view until the onBackground method is not finished.
Thank you.
i don't see any reason for putting the setContentView() in the onPreExecute method, it should be in the onCreate method to avoid any kind of NullPointerException when you will try to find your views, and for your AsyncTask , you should just use the onPostExecute() which is executed after the method doInBackground()
Please try this one, think its work.`class checkCountryAsync extends AsyncTask {
#Override
protected void onPreExecute() {
super.onPreExecute();
setContentView(R.layout.main);
}
#Override
protected String doInBackground(String... aurl) {
CountryTable country = new CountryTable() ;
country.EnterCountry();
return null;
}
}
`
You should try publishProgress() and onProgressUpdate() methods.
Document doc = new Obtainer(context, uri).execute().get();
This code in the activity class renders the Obtainer(which extends AsyncTask) which gets the xml document from the url. This is the onPreExecute method:
protected void onPreExecute() {
super.onPreExecute();
System.out.println("Pre execute began");
exception = null;
dialog = new ProgressDialog(context);
dialog.setMessage("Loading started");
dialog.setIndeterminate(true);
dialog.setCancelable(false);
System.out.println("Preexecute end");
dialog.show();
}
context is set in the Constructor:
public Obtainer(Context c, String addr) {
context = c;
address = addr;
}
During the runtime I can see in the console output both "Pre execute began" and "Preexecute end" but the progress dialog is not shown. What is the probleM?
Use this code, it works for me:
class Obtainer extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(App.this); // App - your main activity class
dialog.setMessage("Please, wait...");
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
// ...
}
#Override
protected void onPostExecute(Void result) {
dialog.dismiss();
}
}
And in your main activity class method call
new Obtainer().execute();
What Context are you passing when you create your Obtainer (AsyncTask subclass)?
If you are using the Application context via getApplicationContext(), it can not be used to create a Dialog (or any View for that matter). You need to pass it a Context that can create Views.
"If you're in the habit of using your application context (from a call to getApplicationContext(), for example) in places where you need a Context to create views, it's only a matter of time until you find a case where things don't work quite like you would want or expect."
From: https://plus.google.com/107708120842840792570/posts/VTeRBsAeyTi
I am using a ProgressDialog to be shown while my background process goes on, but after background process is completed the ProgressDialog is not dismissed still.
Here is my code
private class async extends AsyncTask<String, Void, Boolean> {
final ProgressDialog progressDialog = new ProgressDialog(getParent());
#Override
protected Boolean doInBackground(String... params) {
GetJson json = new GetJson();
boolean success = false;
JSONObject mJsonObject = json
.readJsonObject("url");
try {
success = mJsonObject.getBoolean("success");
} catch (Exception e) {
}
return success;
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
if (progressDialog.isShowing())
progressDialog.dismiss();
}
}
}
#SuppressWarnings("static-access")
#Override
protected void onPreExecute() {
progressDialog.show(getParent(), "Working..", "Please wait...");
}
}
private final class YourTask extends AsyncTask<Void, Void, Object> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = ProgressDialog.show(YourActivity.this, "Title", "Message", true);
}
#Override
protected Object doInBackground(final Void... params) {
// Doing something
}
#Override
protected void onPostExecute(final Object result) {
// Check result or something
dialog.dismiss();
}
}
You can call progressDialog.dismiss() in your AsyncTask's onPostExecute() method.
In onPostExecute() method call dismiss() on your dialog.
I dont know, if you solved this problem, probably yes.
But for next users what will have the same problem (i had it right now too)..
The problem is in your declaration.
final ProgressDialog progressDialog = new ProgressDialog(getParent());
or in your "second" declaration
progressDialog.show(getParent(), "Working..", "Please wait...");
Because in the first one you put in there the getParent parameter (probably MainActivity.this)
and the same you do in calling show method.
Therefore is there 2 parents.. and if you call dismiss() in post execute..it dismiss the first one..but not the another one what have then dialog.isShowing() equal to false.
So important is have there just 1!!!!! parent content..so you can assign the content in declaration with:
new ProgressDialog(content);
or you can do
ProgressDialog dialog=new ProgressDialog();
dialog.setMessage("Loading");
dialog.show(getParent());
and then dismiss it and everything is allright.
or you can do:
ProgressDialog dialog=new ProgressDialog(getParent());
dialog.setMessage("Loading");
dialog.show();
but never give in there twice parents, contents, whatever..
AsyncTasks should not handle at ALL a dialog. Dismissing the dialog in the PostExecute phase can easily lead to an IllegalStateException as the underlying activity can already be destroyed when the dialog gets dismissed. Before destroying the activity the state of the activity will be saved. Dismissing the dialog afterwards will lead to an inconsistent state.