I am creating an application class to perform some version checks during application launch. Below is my class.
public class MyApp extends Application {
public MyApp() {
}
#Override
public void onCreate() {
super.onCreate();
new checkVersionTask().execute(getApplicationContext)
}
private class checkVersionTask extends AsyncTask<Context, Integer, Long> {
#Override
protected Long doInBackground(Context... contexts) {
TODO—version check code
}
protected void onPostExecute(Long result) {
AlertDialog alertDialog;
alertDialog = new AlertDialog.Builder(MyApp.this).create();
alertDialog.setMessage(("A new version of app is available. Would you like to upgrade now?"));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getResources().getString(R.string.Button_Text_Yes), new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.parse("update URL");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE,getResources().getString(R.string.Button_Text_No), new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
}
catch(Exception e){
Toast.makeText(getApplicationContext(), "ERROR:"+e.toString(), Toast.LENGTH_LONG).show();
}
}
}
}
here alertDialog.show is throwing error
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
As I understand this is because the context is not available. In the line
alertDialog = new AlertDialog.Builder(MyApp.this).create();
I tried getApplicationContext() instead of MyApp.this, still the same issue.
Can anyone suggest what's going wrong here. All the Toast statement are working fine.
You can not create a dialog within an application class since, the Dialog should be attached to a window, an Application is not UI class and has no window, so it can't show the dialog.
you can solve it by creating an activity which will show the dialog (you can pass the data as an extra with the intent), and when the data is ready fire and intent and show the dialog
There are two options for giving your AsyncTask the proper context:
1) Use getBaseContext()
I'm not positive if this will work, it seems to function in some situations rather than others.
2) If THAT doesn't work, you'll need to set up a constructor method for your checkVersionTask, as follows.
Context context; //member variable of the checkVersionTask class
public checkVersionTask(Context c) {
this.context = c;
}
Then, when you call the task in your onCreate method, or anywhere in your activity class for that matter, call it like so
new checkVersionTask(MyApp.this).execute();
Whenever you need to access context within the checkVersionTask, just say, for example
alertDialog = new AlertDialog.Builder(context).create();
Related
My android app needs to show a dialog after a delay. The problem is that by the time the dialog is displayed, the context may have changed.
How can I solve this problem?
My code right now looks like this:
class UpdateRunnable extends Runnable {
private Context ctx;
UpdateRunnable(Context ctx) {
this.ctx = ctx
}
#Override
public void run() {
//throws exception: "Unable to add window -- token null is not for an application"
AlertDialog.Builder builder = new AlertDialog.Builder(ctx.getApplicationContext());
builder.setTitle("Time to refresh data");
builder.setMessage("Data needs updating");
builder.show();
}
}
class MyAvtivity extends AppCompatActivity {
#override
public void onCreate(...) {
Handler updateHandler = new Handler();
updateHandler.postDelayed(new UpdateRunnable(this), 10000);
//do some stuff
//start another activity
}
}
AlertDialog.Builder doesn't work with ApplicationContext. That is why you are getting a bad token exception.
So you need to make sure that the context of your runnable is your current activity context, or try a different aproach like using a service with the logic of when to show the dialog inside, and make it notify the current activity that it should show the dialog, or use the service to start an activity with a Dialog.Theme instead of using an AlertDialog.
have you tried with ContextWrapper?
private Context ctx;
UpdateRunnable(Activity activity) { this.activity = activity }
#Override public void run() {
if(!activity.isFinishing()){
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Time to refresh data");
builder.setMessage("Data needs updating");
builder.show();
}
}
I have a splash screen that runs an asyncTask that downloads data from an API. On that task's OnPostExecute I run the next asyncTask to send stored emails. Once that is complete I need an AlertDialog to popup with an ok button so the user knows the downloads are complete. I used this SO question to get as far as I have:
Android AlertDialog inside AsyncTask
Now I'm getting a NullPointerException when I attempt to add properties to the dialog:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
Context c;
public JSONParser(int api,Context c) {
this.api= api;
this.c = c;
}
...
protected void onPostExecute(JSONObject result) {
JSONObject output = new JSONEmailParser(c).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, new String[] {null,null,null,null}).get();
}
}
public class JSONEmailParser extends AsyncTask<String, String, JSONObject> {
Context c;
AlertDialog.Builder builder;
public JSONEmailParser(Context c){
this.c = c;
}
protected void onPreExecute(int api){
builder = new AlertDialog.Builder(SplashScreen.this);
}
...
protected void onPostExecute(JSONObject result) {
setLastUpdate();
builder.setTitle("Sales Toolkit");
builder.setCancelable(false);
builder.setMessage("Download Complete");
builder.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
endSplash();
}
});
builder.show();
}
}
The error is coming up on builder.setTitle("Sales Toolkit");
AsyncTask#onPreExecute() doesn't take an int argument. Since your method has the wrong signature, it is likely never being called, and therefore builder is never set. This is a classic example of why you should use #Override annotations.
Do not use a .get() to execute an AsyncTask as it will not be async anymore. And onPreExecute will not be called?
It seems like the onPreExecute() method is not being called. If you don't really need to use the builder anywhere before the onPostExecute() method, I would suggest just moving
builder = new AlertDialog.Builder(SplashScreen.this);
into the onPostExecute() method.
I have a piece of code to delete an Item in database. I am calling the same code from two different activities. So to avoid code repetition, I want to shift the code to the Application object. The code in one of the activities looks like this:
private void deleteItem() {
AlertDialog.Builder alert = new AlertDialog.Builder(Activity1.this);
alert.setTitle(R.string.confirmTitle);
alert.setMessage(R.string.confirmMessage);
alert.setPositiveButton(R.string.delete_btn,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int button) {
final DbHelper db = new DbHelper(Activity1.this);
AsyncTask<Long, Void, Object> deleteTask = new AsyncTask<Long, Void, Object>() {
#Override
protected Object doInBackground(Long... params) {
db.deleteItem(params[0]);
return null;
}
#Override
protected void onPostExecute(Object result) {
finish();
}
};
deleteTask.execute(new Long[] { rowID });
}
});
alert.setNegativeButton(R.string.cancel_btn, null).show();
}
Now to put it in application object, I changed the function to public, gave it two parameters for input: Context and rowID. But in the onPostExecute method of AsyncTask I have to close the activity. In the activity, I did this by finish(). How do I do it in this context? I have attached the code in application object also.
public void deleteItem(final Context context, final long rowID) {
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle(R.string.confirmTitle);
alert.setMessage(R.string.confirmMessage);
alert.setPositiveButton(R.string.delete_btn,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int button) {
final DbHelper db = new DbHelper(context);
AsyncTask<Long, Void, Object> deleteTask = new AsyncTask<Long, Void, Object>() {
#Override
protected Object doInBackground(Long... params) {
db.deleteItem(params[0]);
return null;
}
#Override
protected void onPostExecute(Object result) {
finish();
}
};
deleteTask.execute(new Long[] { rowID });
}
});
alert.setNegativeButton(R.string.cancel_btn, null).show();
}
Context can be cast to Activity :
Activity activity = (Activity) context;
And than just use :
activity.finish();
Instead of shifting it to Application, create a BaseActivity(which extends Activity class) class, all your activities extend BaseActivity .. and common code will be place in BaseActivity
I think that what you are trying to do is fundamentally not a good idea.
Outside of the Activity code, there are no guarantees that the activity still exists - the memory manager may have cleaned it up, the user may have pressed Back etc.
The final design decision is up to you but I advise you to consider if this is really necessary.
A little redundancy is okay in my opinion if it leads to more program stability and reliability.
Its simple, add activity instance as well
public void deleteItem(final Context context, Activity activity,final long rowID){
activity.finish();
}
It's impossible to call Application.finish() like in C# . You can use method like this :
Activityname.finish();
It's good solution.
I hope I helped.
I'm using a AsyncTask
I use parent to create the intent no errors.
The line to creat a dialog gives a
parent cannot be resolved to a ye.
new parent.AlertDialog.Builder(this)
The error I get is that parent does not exist, but I use parent in the same methed to call the intent
code block
private class SendTextOperation extends AsyncTask {
#Override
protected void onPreExecute() {
//Update UI here
}
#Override
protected String doInBackground(String... params) {
// Talk to server here to avoid Ui hanging
rt=TalkToServer("http://besttechsolutions.biz/projects/bookclub/login.php");
return(rt);
}
#Override
protected void onPostExecute(String result) {
if (rt.contains("ok"))
{
Intent i = new Intent(parent, cChat.class);
startActivity(i);
}
else
{
new parent.AlertDialog.Builder(this)
.setTitle("Game Over")
.setMessage("Your time is up, You saved "
+" Million more people!!")
.setNeutralButton("Try Again",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dlg, int i)
{
}} ).show();
}
}
}
For showing AlertDialog from non Activity you will need to pass Current Activity Context to non Activity class in your case to SendTextOperation class.
Create an Constructor for SendTextOperation as :
public class SendTextOperation extends AsyncTask<String,Void,String>{
Context context;
public SendTextOperation(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
//Update UI here
}
#Override
protected String doInBackground(String... params) {
// Talk to server here to avoid Ui hanging
rt=TalkToServer("http://besttechsolutions.biz/projects/bookclub/login.php");
return(rt);
}
#Override
protected void onPostExecute(String result) {
if (rt.contains("ok"))
{
Intent i = new Intent(context, cChat.class);
startActivity(i);
}
else
{
new context.AlertDialog.Builder(context)
.setTitle("Game Over")
.setMessage("Your time is up, You saved "
+" Million more people!!")
.setNeutralButton("Try Again",new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dlg, int i)
{
}} ).show();
}
}
}
and start SendTextOperation AsyncTask as :
SendTextOperation sendtxtasyncTask = new SendTextOperation(CurrentActivity.this);
sendtxtasyncTask.execute("");
Lets say you have that class declared inside a class named MyActivity
Then use instead of this, MyActivity.this when creating the Dialog.
It looks like you should be calling it like this:
final AlertDialog.Builder builder = new AlertDialog.Builder(_context);
builder.setMessage(_context.getString(R.string.error) + ": " + _errorMessage)
.setTitle(_context.getString(R.string.loginError))
.setIcon(android.R.drawable.ic_dialog_alert)
.setCancelable(true)
.setPositiveButton(_context.getString(R.string.ok), null);
final AlertDialog alert = builder.create();
alert.show();
(My own sample code)
It looks like your error is trying to do parent.AlertDialog.Builder(this), where you need to use new AlertDialog.Builder(parent), if parent is your context.
I display an Alertbox with ok or cancel.
I want to implement an asynch task on the press of OK. Havent done asynch and been struggling with it for awhile. I dont understand where the asych class goes also. Does it go outside the method that is being executed or outside of it? Current code as follows:
private abstract class DoAsynchTask extends AsyncTask<Void,Void,Void>
{
protected void doInBackground()
{
Drawable drawable= getImage(imageSelect);
MakeWallPaper(drawable,1);
}
/* protected void onProgressUpdate(Integer... progress)
{
setProgress(progress[0]);
}*/
protected void onPostExecute()
{
Toast.makeText(getApplicationContext(), "Wallpaper Saved.",Toast.LENGTH_LONG).show();
AlertDialogProcessing=0;
}
}
public void getWallpaper(final View v)
{
if(AlertDialogProcessing==0)
{
final String title="Set Image to Wallpaper";
final String message="Press OK to set as Wallpaper or CANCEL.\nWait after pushing OK.";
final String ok="OK";
final String cancel="CANCEL";
final AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setCancelable(true);
alertbox.setIcon(android.R.drawable.ic_dialog_alert);
alertbox.setTitle(title);
alertbox.setMessage(message);
alertbox.setNegativeButton(cancel, null);
final AlertDialog dlg = alertbox.create();
alertbox.setPositiveButton(ok,new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dlg, int which)
{
DoAsynchTask.execute(null,null,null); //<<<<Wrong
dlg.dismiss();
Vibrate(ClickVibrate);
}
});
alertbox.setNegativeButton(cancel,new DialogInterface.OnClickListener(){ public void onClick(DialogInterface arg0, int arg1){AlertDialogProcessing=0;
Vibrate(ClickVibrate); } });
alertbox.show();
}
}
There's a couple problems in the code.
1) First of all, the compiler is probably giving you this message:
The type MyActivity.DoAsynchTask must implement the inherited abstract
method
AsyncTask.doInBackground(Void...) MyActivity.java
If you look closely at the error message, you'll realize that what you defined was this:
protected void doInBackground() {
which is not what is needed. Even though it might seem silly, when your AsyncTask subclass takes Void as the generic parameter types, that means that doInBackground() must look like this:
protected Void doInBackground(Void... arg0) {
The compiler complains because you haven't implemented that (exact) method. When you inherit from an abstract class, and fail to implement all of its required/abstract method(s), then you can only get it to compile by marking the subclass as abstract, too. But, that's not really what you want.
So, just change your code to (remove abstract from your class):
private class DoAsynchTask extends AsyncTask<Void,Void,Void>
and
protected Void doInBackground(Void... arg0) {
{
Drawable drawable= getImage(imageSelect);
MakeWallPaper(drawable,1);
return null;
}
2) And the second problem, as others have pointed out, is that you must start your task with:
new DoAsynchTask().execute();
not
DoAsynchTask.execute(null,null,null);
Your code would only be correct if execute() was a static method in AsyncTask, which it's not. In order to invoke the non-static execute() method, you first need a new instance of the DoAsynchTask class. Finally, the null, null, null parameter list is also not necessary, although I don't think it will cause the code to fail either.
Since your doInBackground() does not specify any parameters, you should call DoAsynchTask.execute() without parameters.
Why is your class abstract? Normally an AsyncTask should be an inner class of the activity starting it. So create your dialog in the activity, and execute the AsyncTask when clicking on OK button, like you do.
//final working copy -Thanks ALL
public void getWallpaper(final View v)
{
Vibrate(ClickVibrate);
final class SetWallPaperAsynchTask extends AsyncTask<Void,Void,Void>
{
#Override
protected Void doInBackground(Void... arg0)
{
Drawable drawable= getImage(imageSelect);
MakeWallPaper(drawable,1);
return null;
}
#Override
protected void onPostExecute(Void result)
{Toast.makeText(getBaseContext(), "Wallpaper Saved.", Toast.LENGTH_LONG).show();
AlertDialogProcessing=0;
}
}
if(AlertDialogProcessing==0)
{
ProgressDialog progress;
final String title="Set Image to Wallpaper";
final String message="Press OK to set as Wallpaper or CANCEL.";
final String ok="OK";
final String cancel="CANCEL";
final AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setCancelable(true);
alertbox.setIcon(android.R.drawable.ic_dialog_alert);
alertbox.setTitle(title);
alertbox.setMessage(message);
alertbox.setNegativeButton(cancel, null);
final AlertDialog dlg = alertbox.create();
alertbox.setPositiveButton(ok,new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface arg0, int arg1)
{
new SetWallPaperAsynchTask().execute();
dlg.dismiss();
Vibrate(ClickVibrate);
}
});
alertbox.setNegativeButton(cancel,new DialogInterface.OnClickListener(){ public void onClick(DialogInterface arg0, int arg1){AlertDialogProcessing=0; Vibrate(ClickVibrate); } });
alertbox.show();
}
}