I'm writing a custom library, and I ran into a problem. I need to display a dialog to prompt a user to login one time. I can't seem to be able to display an AlertDialog from the Library. I get Unable to add window -- token is not for an application. I am getting the context of the application, by extending a custom library application class. This is the application class in the library:
public class MyCustomApplication extends Application {
private static MyCustomApplication instance;
/**
* Constructor.
*/
public MyCustomApplication () {
instance = this;
}
/**
* Gets the application context.
*
* #return the application context
*/
public static Context getContext() {
return instance;
}
And this is the code in the app that is using the library:
public class MyApplication extends MyCustomApplication {
#Override
public void onCreate(){
super.onCreate();
}
This is the code in the library that attempts to display a dialog:
public static void displayTerminatePopup(String title, String message){
int size = 14;
AlertDialog.Builder aboutBuilder = new AlertDialog.Builder(MyCustomApplication.getContext());
aboutBuilder
.setTitle(title)
.setMessage(message)
.setCancelable(false);
.setPositiveButton("Accept",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel();
}
});
final AlertDialog aboutAlert = aboutBuilder.create();
aboutAlert.show();
TextView textView = (TextView) aboutAlert.findViewById(android.R.id.message);
textView.setTextSize(size);
}
The 'MyCustomApplication.getContext() is where I'm 99% sure the hang up is. I also tried passing a Context directly to the library, and that didn't work, either. Any help on how to show a dialog to allow a user to login via a library would be much appreciated. I've been searching and searching and havn't been able to find anything.
Thanks!
Related
I am currently developing an application using Xamarin.Forms that will be available on the Android and iOS platforms. When the application is first loaded on device, I check to see if there is an internet connection available on the device. I want to display a dialog box if an internet connection is not available.
Here is the following snippet of code I am using to check the internet on the Xamarin.Forms.ContentPage
if(App.Connectivity.IsNetworkConnectivityAvailable())
{
App.Notification.DisplayLocalNotifications("No Internet", "You need an internet connection to access certain application content");
}
I am using dependency injection to build the appropriate module for handling dialog boxes for each appropriate environment. The Android is throwing the following exception
Android.Views.WindowManagerBadTokenException: Unable to add window --
token null is not for an application Here is the code for the
DisplayLocalNotification method on the Android:
public void DisplayLocalNotification(string title, string content)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Application.Context)
.SetTitle(title)
.SetMessage(content)
.SetCancelable(true)
.SetPositiveButton("OK", (EventHandler<DialogClickEventArgs>) null);
AlertDialog alert = builder.Create();
alert.Show();
var okBtn = alert.GetButton((int)DialogButtonType.Positive);
okBtn.Click += (sender, args) =>
{
alert.Dismiss();
};
}
After doing some research, I need to get pass the current activity to the AlertDialog.Builder constructor instead of the Application.Context. How do I get the current activity object from the application context when you need to the activity outside of the activity context?
Xamarin.Forms Android platform code should assign the current Activity into Forms.Context property. This is the static Forms class and if you debug it you will see that the Forms.Context is an Activity.
public static class Forms
{
public static Context Context { get; }
public static bool IsInitialized { get; }
public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
public static void Init(Activity activity, Bundle bundle);
}
There is some questions already close to this question but they haven't been very helpful for me. So here comes a new one.
I have an Activity which has two tabs. Each tab contains a ListFragment (SherlockListFragment to be exact). One tab shows a list of shopping list objects and the other shows a list of recipe objects. Now I want to create a DialogFragment for renaming a list or a recipe or any other object I might later add to the application.
The solution provided here sounded promising but because ListFragment can not be registered to listen clicks from the dialog I should make my Activity to listen them which is not ideal because then my Fragments would not be independent.
How to get data out of a general-purpose dialog class
Ideally I would like to have my rename dialog as independent and reusable as possible. This far I have invented just one way to do this. Sending the objects className and id to the dialog and then using switch case to fetch the correct object from the database. This way the dialog would be able to update the objects name by itself (if the object has rename method). But the requery to the database sounds just dump because the ListFragment has the object already. And then the dialog would need a new case in the switch for each new kind of object.
Any ideas?
I actually just created a similar sort of dialog fragment to what you're asking about. I was for a fairly large app and it was getting kind of ridiculous the amount of dialog listeners our main activity was extending just to listen for the results of a single dialog.
In order to make something a bit more flexible I turned to using ListenableFuture from Google's Guava concurrent library.
I created the following abstract class to use:
public abstract class ListenableDialogFragment<T> extends DialogFragment implements ListenableFuture<T> {
private SettableFuture<T> _settableFuture;
public ListenableDialogFragment() {
_settableFuture = SettableFuture.create();
}
#Override
public void addListener(Runnable runnable, Executor executor) {
_settableFuture.addListener(runnable, executor);
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
return _settableFuture.cancel(mayInterruptIfRunning);
}
#Override
public boolean isCancelled() {
return _settableFuture.isCancelled();
}
#Override
public boolean isDone() {
return _settableFuture.isDone();
}
#Override
public T get() throws InterruptedException, ExecutionException {
return _settableFuture.get();
}
#Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return _settableFuture.get(timeout, unit);
}
public void set(T value) {
_settableFuture.set(value);
}
public void setException(Throwable throwable) {
_settableFuture.setException(throwable);
}
// Resets the Future so that it can be provided to another call back
public void reset() {
_settableFuture = SettableFuture.create();
}
#Override
public void onDismiss(DialogInterface dialog) {
// Cancel the future here in case the user cancels our of the dialog
cancel(true);
super.onDismiss(dialog);
}
Using this class I'm able to create my own custom dialog fragments and use them like this:
ListenableDialogFragment<int> dialog = GetIdDialog.newInstance(provider.getIds());
Futures.addCallback(dialog, new FutureCallback<int>() {
#Override
public void onSuccess(int id) {
processId(id);
}
#Override
public void onFailure(Throwable throwable) {
if (throwable instanceof CancellationException) {
// Task was cancelled
}
processException(throwable);
}
});
This is where GetIdDialog is a custom instance of a ListenableDialogFragment. I can reuse this same dialog instance if needs be by simply calling dialog.reset in the onSuccess and onFailure methods to ensure that the internal Future gets reloaded for adding back to a callback.
I hope this helps you out.
Edit: Sorry forgot to add, in your dialog you can implement an on click listener that does something like this to trigger the future:
private class SingleChoiceListener implements DialogInterface.OnClickListener {
#Override
public void onClick(DialogInterface dialog, int item) {
int id = _ids[item];
// This call will trigger the future to fire
set(id);
dismiss();
}
}
I would maybe just using a static factory pattern of some variation to allow dynamic initialization of the DialogFragment.
private enum Operation {ADD, EDIT, DELETE}
private String title;
private Operation operation;
public static MyDialogFragment newInstance(String title, Operation operation)
{
MyDialogFragment dialogFragment = new DialogFragment();
dialogFragment.title = title; // Dynamic title
dialogFragment.operation = operation;
return dialogFragment;
}
Or.. and I would recommend this more, have a static factory method for each type of operation you will use it for. This allows different dynamic variations to be more concrete and ensures that everything works together. This also allows for informative constructors.
Eg.
public static MyDialogFragment newAddItemInstance(String title)
{
MyDialogFragment dialogFragment = new DialogFragment();
dialogFragment.title = title; // Dynamic title
return dialogFragment;
}
public static MyDialogFragment newEditItemInstance(String title)
{
MyDialogFragment dialogFragment = new DialogFragment();
dialogFragment.title = title; // Dynamic title
return dialogFragment;
}
And then of course create an interface that every calling Activity / Fragment (in which case you need to set this Fragment as the targetFragment and get reference to that target Fragment in your DialogFragment) so that the implementation is taken care of in the target Fragment and nothing to do with the DialogFragment.
Summary: There are various ways of going about this, for simplicity, I would stick with some form of static factory pattern and make clever use of interfaces to separate any the logic from the DialogFragment hence making it more reusable
EDIT: From your comment I would suggest you look at two things:
Target Fragments (See the comment I made on your question). You can invoke methods in your ListFragment from your DialogFragment.
Strategy Pattern. How does the Strategy Pattern work?. This allows you to perform the same operation (with various tailored implementation for each type) on different objects. Very useful pattern.
I have to make a Android Junit Test.
And the source just like this way:
public class A extends Activity{
private classB mB;
private int mType = 2;
somebutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mB.showDialog(
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//next line is the modified and I have to make test file
mB.setType(mType);
}
}
)
}
}
}
And I could let the test click button and prepare all other needed things, but I want to how to assertTrue? And there is no "getType()" and the "Type" in "mB" is private.
Thank you for your time.
Unit-Testing is diffucult on android because all the SDK classes are stubbed out and are good only for compiling agains them, and running unit tests on device or emulator is PITA
Alternative is mocking. [Most] Suitable mock framework is JMockit ( it can mock final private static - also everything you can dream of)
Here is small example showcasing using of jmockit against android classes:
/**
* shall inject assignable views into
*/
#Test
public void testSimpleInjection(#Mocked final WithInjectableViews injectable,
#Mocked final TextView textView,
#Mocked final Button button) {
new Expectations() {
{
injectable.findViewById(239);
returns(textView);
injectable.findViewById(555);
returns(button);
}
};
ViewInjector.startActivity(injectable);
assertEquals(textView, Deencapsulation.getField(injectable, "asView"));
assertEquals(button, Deencapsulation.getField(injectable, "button"));
assertNull(Deencapsulation.getField(injectable, "notInjected"));
}
class WithInjectableViews extends Activity {
// shall be injected
#InjectView(id = 239)
private android.view.View asView;
#InjectView(id = 555)
private Button button;
// shall be left alone
private View notInjected = null;
}
(full source: https://github.com/ko5tik/andject/blob/master/src/test/java/de/pribluda/android/andject/ViewInjectionTest.java)
However, it is diffucult to mock up anonymous inner classes, so you may have to refactor somehow. As to access to provate fields and mewthods - jmockit provides untility class Deencalsulation - it ignores almost all access constraints.
I am not sure I did the right thing. The main reason for my doubts is that I cannot find, in this or other forums, someone who has done a similar thing.
I created an abstract java class in my project. Named it lib. I put there several structures and methods used by all other classes in the project.
It works for me, but I want to know if there is a more accepted method of gathering all common methods and structures.
Note: All methods of course are declared as public static.
Note II: I did not know how to get the context within the abstract class, so if needed I had to pass it as argument to the method.
Is this wat you are looking for?
public abstract class AbstractActivity extends Activity{
public static synchronized boolean showAlertBox(Context ctx,final String title,final String message,final String okBtnTxt,final OnClickListener clickListener){
AlertDialog.Builder alertbox; alertbox = new AlertDialog.Builder(ctx);
this.runOnUiThread(new Runnable() {
#Override
public void run() {
alertbox.setTitle(title);
alertbox.setMessage(message);
if(okBtnTxt!=null || clickListener!=null)
alertbox.setNeutralButton(okBtnTxt,clickListener);
alertbox.show();
.....
}
});
return true;
}
}
In the class extending this abstract class you can just call it by using showAlertBox(this);
Other wise use AbstractActivity.showAlertBox(Context);
Well, thanks to #Matt Wolfe's comment I came to know that what I did is called "Utility class" and it is widely used to share common code in a project.
The general template is:
public abstract class lib {
public static final int ZERO = 0;
public static final int ONE = 1;
public static final int TWO = 2;
public static void func1(int i) {
}
public static void func2(int i, String s) {
}
}
and you can use it like this from any other code:
...;
lib.func1( lib.ZERO );
lib func2( lib.TWO, "sandwich" );
...;
Knowing that makes me confident that what I did is OK.
It would be perfect to find a way to avoid the prefix lib. and just have ECLIPSE, and the compiler, find the right import and recognize the function with just its name, like they do for global libraries.
I want to create a single class which I can call when I need to show an AlertDialog with the parameters and son on I want.
The problem is I dont know if that class have to be an Activity... the alertDialog needs an context, but I can send the current one, because what I want is to show the alert on the actual activity (not to create a new one, I want to show the alert on the actual screen). But I cant get it. I get errors sending the context of the actual activity...
Only I get working it when I create that class like an Activity, but with that, the alertDialog appears alone without the actual screen behind.
What Can I do? I don't know if I understand the contexts...
Thanks
Your class does not need to extend anything to produce a dialog. You can try this way to produce a static method that creates a dialog for you.
Make sure when you call your method you use THIS and not getApplicationContext()
MyDialogClass.getDialog(this); //good!
MyDialogClass.getDialog(getApplicationContext()); //results in error
That is likely the cause of your error
Example class:
public class MyDialogClass
{
public static AlertDialog getDialog(Context context)
{
Builder builder = new Builder(context);
builder.setTitle("Title").setMessage("Msg").setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id)
{
}
});
return builder.create();
}
}
AynscTask does not need the Context; and no, it doesn't need to be an activity.
http://developer.android.com/reference/android/os/AsyncTask.html
Anyways, you should be able to get the context anytime with no problems. Just do this:
public class MyApplication extends Application{
private static Context context;
public void onCreate(){
super.onCreate();
context = getApplicationContext();
}
public static Context getAppContext() {
return context;
}
}
Then you can get the context from wherever you want with MyApplication.getAppContext(); and pass it on and it should work.