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();
}
}
Related
I am making a simple app to download video from a website using volley.
So when i opened my app for first time everything was fine but when i opened app second time after closing app with back button , then i got a error or warning.
Now i can't use alertDialogs ( process dialogs are working fine) because of it ( app crashed if i did)
i am using singleton class AlertUser for AlertDialogs
public class AlertUser {
private static final AlertUser AlertUserInstance = new AlertUser();
private Context ActivityContext = null;
private AlertUser() { }
public static AlertUser getInstance() {
return AlertUserInstance;
}
public void init(Context ctx) {
if (ActivityContext == null)
ActivityContext = ctx;
}
public void alertUser(String msg) {
if (!((AppCompatActivity)ActivityContext).isFinishing()) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(ActivityContext);
alertDialogBuilder.setTitle(R.string.app_name);
alertDialogBuilder.setMessage(msg);
alertDialogBuilder.setPositiveButton("Got it!",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
}
}
Here is some code from MainActivity
public class MainActivity extends AppCompatActivity {
private RequestQueue queue;
private AlertUser alert = AlertUser.getInstance();
ProgressDialog progressDialog;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
Log.d("Main","onCreate");
alert.init(MainActivity.this);
queue = new Volley().newRequestQueue(MainActivity.this);
}
}
Edit : Now i am using System.exit(0) and now it's working in every run after being killed but i don't think its good solution and still i am unaware from exact problem.
I want to display an alert dialog. And this alert dialog is created in one activity. But Problem is i want to display this dialog on top of any activity in an application when i get some response from server
Yes i got the solution....
first i created a class for displaying alert dialog.
upon receiving a response from server calling a method to display alert dialog by passing application context
package io.omoto.omotokairaliapp.Utls;
import android.content.Context;
import android.view.WindowManager;
import com.gitonway.lee.niftymodaldialogeffects.lib.NiftyDialogBuilder;
import io.omoto.omotokairaliapp.Constants.Constants;
/**
* Created by ${venkie} on ${28/1/16}.
*/
public class DisplayRegisteredMessage {
Context context;
private NiftyDialogBuilder dialogBuilder;
public DisplayRegisteredMessage(Context context) {
this.context = context;
}
public void displayMessage() {
if (Constants.FLAG == 1) {
Constants.FLAG = 0;
dialogBuilder = NiftyDialogBuilder.getInstance(context);
dialogBuilder
.withTitle("Response is already registered")
.withMessage("For this Customer we have already taken response Sorry!!");
dialogBuilder.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialogBuilder.show();
} else {
}
}
}
The above code displays alert dialog
#Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
super.onSuccess(statusCode, headers, response);
Log.e("response page", response.toString());
try {
if (response.getString(Constants.STATUS).equalsIgnoreCase("SUCCESS"))
p7.deleterecord(p7b.getFlowid());
p7.deleteRows();
Constants.FLAG = 1;
DisplayRegisteredMessage displayRegisteredMessage = new DisplayRegisteredMessage(mContext);
displayRegisteredMessage.displayMessage();
} catch (JSONException e) {
e.printStackTrace();
}
Log.e("Page 6", p7b.getFlowid());
}
Create alert dialog in other class (not activity) as shown below code in static method & call this method using UDF.showAlertDialog(activity) where you want to show dialog.
public class UDF {
public static void showAlertDialog(
String warning,
DialogInterface.OnClickListener positiveClickListener,
DialogInterface.OnClickListener negativeClickListener,
Context context) {
AlertDialog.Builder alertdialog = new AlertDialog.Builder(context);
alertdialog.setMessage(warning);
alertdialog.setPositiveButton("Ok", positiveClickListener);
alertdialog.setNegativeButton("Cancel", negativeClickListener);
alertdialog.show();
}
}
Edit : set this
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
and add permission in menifest.xml
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
& pass getApplicationContext() while creating dialog instade of activity or context
Here is a workaround that worked for me:
Suppose you have 4 activities in total:
MainActivity
OtherActivity1
OtherActivity2
OtherActivity3
I had the code for the alert dialog in the MainActivity and I wanted the alert dialog to display in all activities. I did the following:
Make other activities extend the main activity.
public class OtherActivity1 extends MainActivity{
}
public class OtherActivity2 extends MainActivity{
}
public class OtherActivity3 extends MainActivity{
}
In your Main activity, save the context in a variable.
public class MainActivity extends AppCompatActivity{
public static Context contextMain;
#Override
protected void onCreate(Bundle savedInstanceState) {
contextMain = MainActivity.this;
}
}
And wherever you are trying to call your alert dialog in the MainActivity just pass contextMain as the context.
final AlertDialog.Builder dialog = new AlertDialog.Builder(contextMain)
Dear Folks,
I am currently working on a android app where I need to show the progress dialog. I need to have a context object for this.
This task I am implementing in the class which extends the application. But every time when I tried to access context object it is showing me the WindowManager.BadTokenException for this line
Dialog dialog=ProgressDialog.show(getApplicationContext(), "Status", "Downloading The master");
Please help me where I am doing wrong
Edit:
Below is my code!
public class FlightStatus extends Application {
private Context context;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
SharedPreferences preference=getSharedPreferences("FlightStatus", 1);
if(preference.getBoolean("firstLaunch", true))
{
try {
Dialog dialog=ProgressDialog.show(getApplicationContext(), "Status!", "Downloading The master!!");
XLSReadHelper excelReader=new XLSReadHelper(getApplicationContext());
//excelReader.readExcelFile(Environment.getExternalStorageDirectory()+"/UHCPAudit/cases.xls");
excelReader.readExcelFile();
Log.d("Excel Operation ", "records read!!");
preference.edit().putBoolean("firstLaunch", false).commit();
dialog.dismiss();
} catch (Exception e) {
// TODO: handle exception
Log.d("Excel Operation ", e.getMessage());
}
}
}
}
It is incorrect to try getting Context inside Application, as no Activity is yet initialized at this stage. Instead show your dialog from Activity/Fragment.
If you are showing the progress dialog from an Activity, use:
Dialog dialog = ProgressDialog.show(MyActivity.this, "Status", "Downloading The master");
If you are showing it from a Fragment, then first add this member to your Fragment class:
private Activity activity;
Then call this in your onCreateView() method:
activity = getActivity();
and finally
Dialog dialog = ProgressDialog.show(activity, "Status", "Downloading The master");
You can use a constructor which takes the Activity as context
public class YourClass extends Application{
private Activity context;
public YourClass(Activity context){
this.context = context;
}
}
And then from your calling Activity:
YourClass yourClass = new YourClass(this);
You can also try to use the ProgressDialog in your Activityitself, in a method which you can call from your custom class:
public void showProgress(){
//Your progress code
}
And in your custom class:
context.showProgress();
I have an activity that popup instructions the first time the app runs ( In a DialogFragment).
I want to stop the execution of code while user don't dismiss the Dialog.
Is it posible to do it???
EDIT:
I try to use CountDownLatch but it is freezing my UI, and the Dialog is not showing.
Activity :
private CountDownLatch startSignal;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// open tutorial if need
startSignal = new CountDownLatch(1);
TutorialDialog tutoDial = new TutorialDialog();
tutoDial.show(getSupportFragmentManager(), "tuto");
try {
toast("aguardando");
startSignal.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Dialog ( I just put the needed methods) :
public class TutorialDialog extends DialogFragment {
private final String TAG = getClass().getSimpleName();
MapActivity parentActivity;
SharedPreferences preferences;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
parentActivity = ((MapActivity) activity);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// setStyle(DialogFragment.STYLE_NORMAL, 0);
AlertDialog.Builder principal = new AlertDialog.Builder(getActivity());
principal.setInverseBackgroundForced(true);
// principal.setTitle(R.string.report);
View view = getActivity().getLayoutInflater().inflate(
R.layout.tutorial, null);
TextView ok = (TextView)view.findViewById(R.id.ok);
ok.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
parentActivity.resumeCode();
dismiss();
}
});
AlertDialog ad = principal.create();
return ad;
}
}
And in the Activity, the method resumeCode():
public void resumeCode(){
startSignal.countDown();
toast("whats next");
}
EDIT 2: I implement it several times. My last implementation should be the one, but it still don't work. I will try to explain how it goes.
mainActivity ( Main thread) launch the dialogFragment:
TutorialDialog tutoDial = new TutorialDialog();
tutoDial.setCancelable(true);
tutoDial.show(getSupportFragmentManager(), "tuto");
Then, in another thread, I run await() in onPreExecute():
public class GetPlaces extends AsyncTask> {
private ProgressDialog dialog;
// I put it public so that I can reach it from the DialogFragment
public static CountDownLatch startSignal = new CountDownLatch(1);
#Override
protected void onPreExecute() {
super.onPreExecute();
try {
startSignal.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dialog = new ProgressDialog(context);
dialog.setCancelable(false);
dialog.setMessage(context.getString(R.string.loading));
dialog.isIndeterminate();
dialog.setProgressStyle(R.style.dialogInput);
dialog.show();
}
This way, it should not run before the startSignal variable reach 0
Then, In my FragmentDialog, when the dialog dismiss, I run :
noTuto.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// DISMISS DIALOG
startSignal.countDown();
dismiss();
}
});
So in theory, it should work, but in the ugly reality, my FragmentDialog freeze...
What I'm sure :
1 - there is no startSignal.await(); in mainActivity that should freeze UI anymore
2 - The startSignal variable is define in another thread:
public class GetPlaces extends AsyncTask<Void, Void, ArrayList<Place>>
so, if anything freeze, it should be this thread, but I don't understand why my dialog is the one which is freezing. Right now, my dialog does not receive clicks anymore...
Use CountDownLatch startSignal = new CountDownLatch(1);
Your code will usually be executed in user thread. Make your user thread code startSignal.await(); so that it can pause its execution.
Your DialogFragment will be executed in UI thread. Make your UI thread code startSignal.countDown(), to resume your user thread code execution.
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();