web-dev-qa-db-fra.com

Afficher une alerte de dialogue à partir d'une classe de non activité dans Android

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);
}
8
Saqib

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.

13
Pankaj Kumar

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" />
34
Eliran Kuta

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é.

6
Chris Sullivan

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();
    }
1
Sunil Kumar

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)

0
XLE_22

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.


  1. 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.


  1. Lors de l'appel de la méthode 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;
}


3. Puisque nous avons maintenant le contexte de l'activité, nous pouvons l'utiliser pour créer une fonction avec un dialogue d'alerte en utilisant la méthode 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 :)

0
lighthouse64

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");
0
linuxgnuru