Je souhaite afficher une boîte de dialogue d'alerte via la classe AlertDialogManager
à la méthode DeviceAdminReceiverSample
de non-activity
class onDisabled
, mais chaque fois que j'appelle alertDialog
via cette méthode, une erreur est générée avec le texte suivant
Erreur
06-12 12:01:19.923: E/AndroidRuntime(468): FATAL EXCEPTION: main
06-12 12:01:19.923: E/AndroidRuntime(468): Java.lang.RuntimeException: Unable to start
receiver com.Android.remotewipedata.DeviceAdminReceiverSample:
Android.view.WindowManager$BadTokenException: Unable to add window -- token null is not
for an application
Je sais que le problème est lié à la chose context
mais je ne sais pas quoi y mettre pour que cela fonctionne, j’ai essayé this
, getApplicationContext()
mais tout en vain. Mon code pour les deux classes est ci-dessous
AlertDialogManager
public class AlertDialogManager {
public void showAlertDialog(Context context, String title, String message,
Boolean status) {
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle(title);
alertDialog.setMessage(message);
if (status != null)
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
}
});
alertDialog.show();
}
}
DeviceAdminReceiverSample
public class DeviceAdminReceiverSample extends DeviceAdminReceiver {
static final String TAG = "DeviceAdminReceiver";
AlertDialogManager alert = new AlertDialogManager();
/** Called when this application is no longer the device administrator. */
@Override
public void onDisabled(Context context, Intent intent) {
super.onDisabled(context, intent);
Toast.makeText(context, R.string.device_admin_disabled,
Toast.LENGTH_LONG).show();
// intent.putExtra("dialogMessage", "Device admin has been disabled");
// intent.setClass(context, DialogActivity.class);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(intent);
alert.showAlertDialog(context, "Alert",
"Device admin has been disabled", true);
}
Le problème est 'You can show AlertDialogs from Activity only
'. Ce n'est pas une question de contexte.
Bien que ce ne soit pas une bonne idée d’afficher une boîte de dialogue à partir du récepteur(mieux vaut utiliser Notification), mais si vous souhaitez le faire, vous pouvez créer une activité en tant que boîte de dialogue et afficher.
Ajoutez simplement ceci avant votre alertDialog.show();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
or try following is above doesn't works:
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL);
et utiliser cette permission:
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
Si vous souhaitez toujours obtenir l'activité en cours de n'importe où dans l'application, vous pouvez enregistrer un ActivityLifecycleCallback sur votre instance d'application.
Voici une implémentation non testée qui pourrait vous rapprocher.
public class TestApp extends Application {
private WeakReference<Activity> mActivity = null;
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
mActivity.clear();
}
/** Unused implementation **/
@Override
public void onActivityStarted(Activity activity) {}
@Override
public void onActivityResumed(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) {}
@Override
public void onActivityStopped(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
});
}
public Activity getCurrentActivity() {
return mActivity.get();
}
}
Ensuite, pour l'utiliser dans votre application, vous feriez un appel comme ça ...
Activity activity = ((TestApp)getApplicationContext()).getCurrentActivity();
Les avantages sont que vous pouvez toujours garder une trace de votre activité actuelle, cependant c'est un peu trop pour la gestion des dialogues à partir de l'activité.
appeler cette méthode en classe d'activité
public static void showAlert(Activity activity, String message) {
TextView title = new TextView(activity);
title.setText("Title");
title.setPadding(10, 10, 10, 10);
title.setGravity(Gravity.CENTER);
title.setTextColor(Color.WHITE);
title.setTextSize(20);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// builder.setTitle("Title");
builder.setCustomTitle(title);
// builder.setIcon(R.drawable.alert_36);
builder.setMessage(message);
builder.setCancelable(false);
builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
Comme l'a suggéré AJAY, le meilleur moyen consiste à utiliser le paramètre "Activité" au lieu d'utiliser le "contexte".
Dans votre classe personnelle, demandez simplement l’activité dans son constructeur en tant que paramètre obligatoire => public void constructorOfTheClass (Activité d’activité) {...}.
Lorsque vous appelez le constructeur dans votre activité, indiquez simplement ce paramètre et vous pourrez le manipuler directement dans la classe.
Ensuite, vous pouvez utiliser ces informations de type "activité" dans votre méthode AlertDialog au sein de votre classe, car SUNIL a remarqué que l'invite était demandée correctement dans l'activité souhaitée.
J'espère que ça aide ... et soyez sûr que ça va marcher! ; o)
Voici une méthode rapide pour effectuer correctement cette tâche qui a fait le travail pour moi. Fondamentalement, vous ne feriez que créer un nouveau fil.
Déclarez une variable publique et statique avec un type correspondant à la classe d'activité d'origine.
public static Activity1 activity;
Activity1 est la classe dans laquelle réside la variable.
onCreate();
, définissez la variable pour qu'elle soit égale au contexte de l'activité, également connue sous le nom de this .Exemple:
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
activity = this;
}
runOnUiThread();
à l'intérieur de la fonction qui appellera le dialogue d'alerte. Nous utiliserions un new Runnable()
pour l'action exécutable requise pour runOnUiThread();
, et pour que la boîte de dialogue d'alerte soit réellement ouverte, nous remplacerions la fonction d'exécution d'un élément exécutable et y placerions le code.Exemple de fonction:
public static void exampleDialog(){
Activity1.activity.runOnUiThread(new Runnable){
@Override
public void run(){
//alert dialog code goes here. For the context, use the activity variable from Activity1.
}
}
}
J'espère que cela t'aides :)
Voici ce que j'ai fabriqué et utilisé:
myDialog.Java:
import Android.app.Activity;
import Android.content.DialogInterface;
import Android.support.v7.app.AlertDialog;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.widget.TextView;
public class myDialog {
private Activity mActivity;
myDialog(Activity a) {
this.mActivity = a;
}
@SuppressWarnings("InflateParams")
public void build(String title, String msg) {
LayoutInflater inflater = LayoutInflater.from(mActivity);
View subView = inflater.inflate(R.layout.dialog_box_text, null);
final TextView message = subView.findViewById(R.id.message);
message.setText(msg);
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(title);
builder.setView(subView);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
dialog_box_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:weightSum="1"
Android:orientation="horizontal">
<TextView
Android:id="@+id/message"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:text=" "
Android:maxLines="1"
Android:textColor="@color/colorBlack" />
</LinearLayout>
Exemple de code:
public class MainActivity extends AppCompatActivity {
private myDialog md;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
md = new myDialog(this);
...
md.build("Title", "Message");