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.
Related
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 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();
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();
}
}
my issue is the same as this
Instance variable of Activity not being set in onPostExecute of AsyncTask or how to return data from AsyncTask to main UI thread
but i want to send the data back to the same calling activity. Doesnt startActivity for intents always restart the activity
On option is to use listeners, where you create an interface that your activity implents, something like:
public interface AsyncListener {
public void doStuff( MyObject obj );
}
That way, if you're subclassing AsyncTask, it is easy to add this listener, then in onPostExecute(), you could do something like:
protected void onPostExecute( MyObject obj ) {
asyncListener.doStuff(obj);
}
This depends on your class structure, but if your AsyncTask is a class within your Activity then you can reference methods of that activity.
What you would do is in your onPostExecute method call a function of your Activity that passes some data that was retrieved in the AsyncTask to the activity where you can then use it..
The code would look like this
class YourActivity extends Activity {
private static final int DIALOG_LOADING = 1;
public void onCreate(Bundle savedState) {
setContentView(R.layout.yourlayout);
showDialog(DIALOG_LOADING);
new LongRunningTask1().execute(1,2,3);
}
protected Dialog onCreateDialog(int dialogId) {
switch(dialogId) {
case DIALOG_LOADING:
ProgressDialog pDialog = new ProgressDialog(this);
pDialog.setTitle("Loading Data");
pDialog.setMessage("Loading Data, please wait...");
return pDialog;
default:
return super.onCreateDialog(dialogId);
}
}
private void onBackgroundTaskDataObtained(List<String> results) {
dismissDialog(DIALOG_LOADING);
//do stuff with the results here..
}
private class LongRunningTask extends AsyncTask<Long, Integer, List<String>> {
#Override
protected void onPreExecute() {
//do pre execute stuff
}
#Override
protected List<String> doInBackground(Long... params) {
List<String> myData = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
try {
Thread.sleep(params[i] * 1000);
myData.add("Some Data" + i);
} catch(InterruptedException ex) {
}
}
return myData;
}
#Override
protected void onPostExecute(List<String> result) {
YourActivity.this.onBackgroundTaskDataObtained(result);
}
}
}
So the typical flow is like this, set the view of the current page, and then show a progress dialog. Right after that start the async task (or whenever, it doesn't matter really).
After your async task is complete, call a function of the activity and pass it the data.
Don't use shared data within the async task or you risk issues with threading.. Instead once you are done with it pass it to the activity. If you want to update the view progressively while doing work you can use on onProgressUpdate