I am running an Async(doInBackground) task in android.
I need to populate a progress bar for the task. So i am showing a progressDialog in onPreExecute,
The signature of ProgressDialog.show is Show(Context,Title,message)
But what would be the Context here?
#Override
protected void onPreExecute()
{
progress = ProgressDialog.show(???, "Loading", "Please Wait");
}
Create a constructor for your AsyncTask that takes a context as a parameter.
public class async extends AsyncTask<String, Integer, String>{
private Context context;
public async(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
// Manipulate progress bar
}
Then use this to execute it
async mTask = new async(context).execute(params);
Context can be only of Activity ,Service or Brodcast not of any other class like Asyncktask.So put the Context of that Activity where you are using that AsyncTask class.
You can pass the activity context in the AsyncTask constructor to create the ProgressDialog :
MyAsyncTask constructor :
public MyAsyncTask(Context context){
progressDialog = new ProgressDialog(context, "Loading", "Please wait...");
}
onPreExecute method :
#Override
protected void onPreExecute()
{
progressDialog.show();
}
or store the context and create the dialog in the onPreExecute methods (but I prefer use the first way) :
public class MyAsyncTask extends AsyncTask{
private Context mContext;
public MyAsyncTask(Context context){
this.mContext = context;
}
#Override
protected void onPreExecute()
{
progress = ProgressDialog.show(this.mContext, "Loading", "Please Wait");
}
}
And in activity when you declare MyAsyncTask, you pass the activity:
MyAsyncTask asyncTask = new AsyncTask(this);
asynchTask.execute();
Add this function in your class
private Context getDialogContext() {
Context context;
if (getParent() != null)
context = getParent();
else
context = this;
return context;
}
In your asynctask use it as follows
#Override
protected void onPreExecute()
{
progress = ProgressDialog.show(getDialogContext(), "Loading", "Please Wait");
}
if you want to use only this as context then your Asynctask should be written as an inner class of a class which extends the Activity class. Then your context is the name of the class which extends Activity. Still it is better practice to pass the context like this:
ClassExtendingActivity.this
you can pass current activity view reference like MainActivity.this
Related
I have a top-level Fetch class that extends AsyncTask and I have a MainActivity. I can't get the Fetch class to make a toast due to not having an instance of the MainActivity or its context. I have tried to pass the MainActivity to the Fetch class but it potentially leaks memory. I have tried setting a WeakReference instance of the context, but I can't make a toast from that.
I have read many other posts about this and most seem to have a static inner-class but mine is top-level and I would prefer to keep it that way.
The MainActivity creates an instance of Fetch and then executes it.
public class Fetch extends AsyncTask<Void, Integer, List<List<String>>>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected List<List<String>> doInBackground(Context... params)
{
// run tasks
}
#Override
protected void onProgressUpdate(Integer... progress)
{
}
#Override
protected void onPostExecute(List<List<String>> result)
{
super.onPostExecute(result);
}
}
One way, in doInBackground:
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(<your class name>.this, "hello", Toast.LENGTH_SHORT).show();
}
});
Or in onPostExecute(which invoked on the UI thread after the background computation finishes)
Toast.makeText(<your class name>.this, "hello", Toast.LENGTH_SHORT).show();
Edited: if you want to pass context to AsyncTask,you could do like:
public class MyAsyncTask extends AsyncTask<Void, Integer, List<List<String>>>
private final Context mContext;
public MyAsyncTask(final Context context) {
mContext = context;
}
}
And in MainActivity :
final MyAsyncTask task = new MyAsyncTask(getApplicationContext());
task.execute();
Edited again:
I tested WeakReference successfully.
public class ExampleAsyncTask extends AsyncTask {
private WeakReference<Context> contextRef;
public ExampleAsyncTask(Context context) {
contextRef = new WeakReference<>(context);
}
#Override
protected void onPostExecute(Object result) {
Context context = contextRef.get();
if (context != null) {
Toast.makeText(context, "hello", Toast.LENGTH_SHORT).show();
}
}
}
In MainActivity:
new ExampleAsyncTask(MainActivity.this).execute();
yeah,Don't be worry ,you can use the application context.may be as follow:
implement your App.getContext() in your Application.
and use it in your "Fetch" class and execute it in MainThread.
I have a static AsyncTask in my MainActivity. I run this asynctask to download data from a URL. I'm trying to show a progress dialog from the async task but it crashes on this line: private ProgressDialog dialog = new ProgressDialog(mContext);
I pass the context through to the AsyncTask.
Here is my code:
private static class MyTasksParse extends AsyncTask<String, String, JSONObject> {
private Context mContext;
private ProgressDialog dialog = new ProgressDialog(mContext);
public MyTasksParse(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
this.dialog.setCanceledOnTouchOutside(false);
this.dialog.setMessage("Downloading Files... Please Wait...");
this.dialog.show();
}
#Override
protected JSONObject doInBackground(String... args) {
//get the url and parse it
return json;
}
#Override
protected void onPostExecute(JSONObject json) {
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
I have tried casting mContext as an Activity as follows:
private ProgressDialog dialog = new ProgressDialog(mContext); but still the same error.
I'm not sure what I'm doing wrong. If anyone can help out, it would be great! Thanks :)
Since you have NullPointerException beacuse the variable mContext is null at this point:
private static class MyTasksParse extends AsyncTask<String, String, JSONObject> {
private Context mContext;
private ProgressDialog dialog = new ProgressDialog(mContext);
...
...
this will help:
private static class MyTasksParse extends AsyncTask<String, String, JSONObject> {
private Context mContext;
private ProgressDialog dialog;
public MyTasksParse(Context context) {
mContext = context;
dialog = new ProgressDialog(mContext)
}
When you receive the value of context in the constructor then you can instatiate correctly the ProgressDialog =).
mContext is null when you pass it to the constructor of ProgressDialog, thus throwing a NullPointerException.
This should work:
private Context mContext;
private ProgressDialog dialog;
public MyTasksParse(Context context) {
mContext = context;
dialog = new ProgressDialog(mContext);
}
The mContext is null when you initialise the ProgressDialog. That's why the crash is happening.
You need to change:
private ProgressDialog dialog = new ProgressDialog(mContext);
to:
private ProgressDialog dialog;
And initialise the progress dialog in onPreExecute:
dialog = new ProgressDialog(mContext);
You are getting NullPointerException beacuse mContext is null.
You need to init ProgressDialog inside constructor like
public MyTasksParse(Context context) {
mContext = context;
dialog = new ProgressDialog(mContext)
}
I am executing an AsyncTask from inside a DialogFragment but the progress bar is not shown during doInBackground. Here is the code:
public class GetCustomerSoapAsync extends AsyncTask<Void, Void, String>
{
ProgressDialog prg;
ActionBarActivity activity;
GetResponseFromGetCustomer listener;
public GetCustomerSoapAsync(ActionBarActivity activity, GetResponseFromGetCustomer listener)
{
this.activity = activity;
this.listener = listener;
prg = new ProgressDialog(activity);
prg.setMessage("Lütfen Bekleyin");
Log.i("ED","Progress will be shown");
prg.show();
}
#Override protected String doInBackground(Void... params)
{
//some stuff
}
#Override protected void onPostExecute(String s)
{
listener.getResponseFromGetCustomer(s);
if (prg.isShowing())
{
prg.dismiss();
}
}
and where I call it:
public class B1_PhoneNumberFragment extends android.support.v4.app.Fragment
{
...
buttonLogin.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
...
PhoneNumberVerified dialog = new PhoneNumberVerified();
dialog.show(getFragmentManager(), "NumberVerifiedByUser");
}
...
}
....
public class PhoneNumberVerified extends DialogFragment
{
#Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Format of this dialog will be changed
builder.setMessage("Numaranız doğru mu?\n" + "0" + number)
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog,
int id)
{
GlobalApplication.getUser().setPhone(
(excludeParanthesis
(number)));
//AsyncTask is not working properly,
// progress dialog is not shown and code flows before
// response is set to s
GetCustomerSoapAsync getCustomerSoapAsync =
new GetCustomerSoapAsync(
(ActionBarActivity) getActivity(),
new GetResponseFromGetCustomer()
{
#Override
public void getResponseFromGetCustomer
(String s)
{
response = s;
}
});
getCustomerSoapAsync.execute();
Log.i("ED", "Response after GetCustomerSoapAsync callback: " +
response);
}
And finally, maybe because of the flawed flow of the tasks or maybe something else, the callback can't do its job, and response is not set to return value of the AsyncTask.
Thanks for any help!
You should use onPreExecute :
class Task1 extends AsyncTask<Object, Void, String []> {
/** The Progress dialog. */
private final ProgressDialog dialog = new ProgressDialog(YourActivity.this);
/**
* Set the Progress dialog.
*/
protected void onPreExecute()
{
super.onPreExecute();
this.dialog.setMessage("Loading...");
this.dialog.show();
dialog.setCanceledOnTouchOutside(false);
}
protected String[] doInBackground(Object... params) {
///
}
protected void onPostExecute(String [] result)
{
super.onPostExecute(result);
this.dialog.dismiss();
}
}
To call it you should:
Task1 myTask = new Task1();
myTask.execute(stopArrey, start, end);
Hope it helped! :)
You need to operate on the ProgressDialog only on the UI Thread.
The constructor on the asynctask gives great flexibility enough to put the task in it's own class. Note: It's important that any field that is initialized in the Constructor on your custom AsyncTask takes advantage of the java final keyword so the field variables get automatic null for garbage collection.
Solution ProgressDialog code needs to be invoked in onPreExecute() where the task is still on the UI thread.
public class GetCustomerSoapAsync extends AsyncTask<Void, Void, String>
{
ProgressDialog prg;
// use final for fields initialized in a constructor.
final ActionBarActivity activity;
final GetResponseFromGetCustomer listener;
//The example below passes in the ProgressDialog from the caller where it's already shown. Pass it in to have access in the async tasks publish Progress method. Dismiss the ProgressDialog in the listener method; You didn't show your listener so this is just a technique
public GetCustomerSoapAsync(ActionBarActivity activity, GetResponseFromGetCustomer listener, ProgressDialog prg)
{
this.activity = activity;
this.listener = listener;
this.prg = prg;
// or move this code to onPreExecute() where it runs on the UI thread.
// move this code to onPreExecute()
//prg = new ProgressDialog(activity);
//prg.setMessage("Lütfen Bekleyin");
//Log.i("ED","Progress will be shown");
//prg.show();
}
Ok the issue I believe is you have to declare the PD in the layout visible to the user before the Aysnch task is executing.
For example:
//Declare the pd here. Pd private to class.
private ProgressDialog pd;
builder.setMessage("Numaranız doğru mu?\n" + "0" + number)
.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener()
{
....
pd = ProgressDialog.show(getActivity(), "",
"Your Message Here!!!", false);
// Now using a modified constructor call your execute function
//Previous parametes + pd
GetCustomerSoapAsync gCSA = new GetCustomerSoapAsync(...,...,pd);
getCustomerSoapAsync.execute();
}
Then in your Asynch class:
public class GetCustomerSoapAsync extends AsyncTask<Void, Void, String>
{
ProgressDialog prg;
ActionBarActivity activity;
GetResponseFromGetCustomer listener;
public GetCustomerSoapAsync(ActionBarActivity activity, GetResponseFromGetCustomer listener,ProgressDialog pd)
ProgressDialog prg;
{
this.activity = activity;
this.listener = listener;
this.prg = pd;
}
#Override protected String doInBackground(Void... params)
{
//some stuff
}
#Override protected void onPostExecute(String s)
{
listener.getResponseFromGetCustomer(s);
if (prg.isShowing())
{
prg.dismiss();
}
}
Ps: I don't know if you are using fragments as a implementation but if you are you must refer to the same pd you called in the onclick function in the fragment via rootview else you might be calling functions on a progresss dialog that never showed in the first place.
It took my quite a while to get this to work, but It's clearly not best practice. In short, I need to show a dialog when my AsyncTask finishes, but getApplicationContext() does not work, neither does passing it as a parameter when creating the AsyncTask. So I've declared a public variable for the context in my AsyncTask class and set it before I execute:
private OnClickListener clickLoadRefs = new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("H","Clicked Load Refs");
RefreshRefPoints refreshRefPoints = new RefreshRefPoints();
refreshRefPoints.myCtx=v.getContext();
refreshRefPoints.execute(v.getContext());
}
};
private class RefreshRefPoints extends AsyncTask<Context, Integer, Integer> {
private Integer nPoints=0;
public Context myCtx;
private ProgressDialog pd;
protected Integer doInBackground(Context... ctx) {
Log.d("H","doInBackground()");
dbHelper.clearRefPoints();
requestRefPoints();
nPoints = parseRefPointsCSV();
return nPoints;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPreExecute()
{
pd = ProgressDialog.show(myCtx, "Refreshing Reference Points", "Loading...", true,false);
Log.d( "H", "onPreExecute()" );
}
protected void onPostExecute(Integer result) {
pd.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(myCtx);
builder.setTitle("Reference points refresh complete");
builder.setMessage(result+" records loaded");
builder.setPositiveButton("OK",null);
builder.show();
Log.d("H","onPostExecute()");
}...etc
Can anybody just show me the proper way of passing the context?
Thanks
Define a constructor method and pass context a parameter. It would be better.
Here what I meant:
private class RefreshRefPoints extends AsyncTask<Void, Integer, Integer> {
private Integer nPoints=0;
private Context myCtx;
private ProgressDialog pd;
public RefreshRefPoints(Context ctx){
// Now set context
this.myCtx = ctx;
}
}
That's all.
You may also use YourActivityName.this to refer to the activity Context. Because Activites extend Context, so its valid to do so.
Pass context in constructor as
private OnClickListener clickLoadRefs = new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("H","Clicked Load Refs");
RefreshRefPoints refreshRefPoints = new RefreshRefPoints(Your_ActivityName.this);
refreshRefPoints.myCtx=v.getContext();
refreshRefPoints.execute(v.getContext());
}
};
private class RefreshRefPoints extends AsyncTask<Void, Integer, Integer> {
private Integer nPoints=0;
public Context myCtx;
private ProgressDialog pd;
public RefreshRefPoints (Context ctx) {
myCtx = ctx;
}
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