web-dev-qa-db-fra.com

Comment afficher une boîte de dialogue dans Android sans contexte d'activité?

Cela semble être simple, mais je ne trouve de réponse nulle part. J'ai une application Android qui exécute des tâches réseau en arrière-plan. Si une erreur se reproduit, je veux afficher une boîte de dialogue d'erreur. Lorsque la tâche revient, je ne sais pas dans quelle activité se trouve Sur la base de cet article , il semble que nous ne pouvons pas utiliser le contexte de l'application pour afficher une boîte de dialogue (et en effet j'obtiens le plantage si j'essaye).

Alors, comment puis-je obtenir le contexte de l'activité en cours? Encore une fois, le récepteur de la tâche réseau s'exécute dans le contexte de l'application, pas dans une activité particulière. D'autres idées?

Edit: je dois clarifier. Je ne veux pas afficher de boîte de dialogue d'erreur si je ne suis pas l'application de premier plan. Je ne suis intéressé que par le cas où notre application est au premier plan pour le moment.

34
ManicBlowfish

Si une erreur revient, je souhaite afficher une boîte de dialogue d'erreur.

Veuillez ne le faire que si vous savez que l'utilisateur utilise activement votre application. L'utilisateur sera très très ennuyé si vous les interrompez au milieu d'autre chose (jouer à un jeu, regarder un film, lire un livre).

Alors, comment puis-je obtenir le contexte de l'activité en cours?

Non. Tout au plus, vous indiquez à l'activité en cours qu'elle doit faire quelque chose.

D'autres idées?

Une possibilité consiste à utiliser une diffusion ordonnée, donc si vous avez une activité de premier plan, elle prend le contrôle, sinon vous augmentez un Notification pour informez l'utilisateur du problème sans ouvrir de boîte de dialogue. L'activité qui reçoit la diffusion ordonnée peut afficher un AlertDialog ou autrement informer l'utilisateur du problème. J'ai écrit sur les détails de la façon de procéder dans un article de blog (et n chapitre de livre , d'ailleurs), et voici un exemple d'application démontrant la technique.

Ou, demandez à l'appel de service startActivity() de démarrer ne activité sur le thème de la boîte de dialogue .

26
CommonsWare

J'ai créé une classe d'assistance qui implémente l'idée de CommonsWare. Les activités qui souhaitent afficher des alertes doivent simplement appeler Alerts.register () et Alerts.unregister (). Ensuite, n'importe qui peut appeler Alerts.displayError ().

Commentaires bienvenus.

public class Alerts {

    private static class AlertReceiver extends BroadcastReceiver {

        private static HashMap<Activity, AlertReceiver> registrations;
        private Context activityContext;

        static {
            registrations = new HashMap<Activity, AlertReceiver>();
        }

        static void register(Activity activity) {
            AlertReceiver receiver = new AlertReceiver(activity);
            activity.registerReceiver(receiver, new IntentFilter(MyApplication.INTENT_DISPLAYERROR));
            registrations.put(activity, receiver);
        }

        static void unregister(Activity activity) {
            AlertReceiver receiver = registrations.get(activity);
            if(receiver != null) {
                activity.unregisterReceiver(receiver);
                registrations.remove(activity);
            }
        }

        private AlertReceiver(Activity activity) {
            activityContext = activity;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            abortBroadcast();
            String msg = intent.getStringExtra(Intent.EXTRA_TEXT);
            displayErrorInternal(activityContext, msg);
        }
    }

    public static void register(Activity activity) {
        AlertReceiver.register(activity);
    }

    public static void unregister(Activity activity) {
        AlertReceiver.unregister(activity);
    }

    public static void displayError(Context context, String msg) {
        Intent intent = new Intent(MyApplication.INTENT_DISPLAYERROR);
        intent.putExtra(Intent.EXTRA_TEXT, msg);
        context.sendOrderedBroadcast(intent, null);
    }

    private static void displayErrorInternal(Context context, String msg) {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("Error")
               .setMessage(msg)
               .setCancelable(false)
               .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                   public void onClick(DialogInterface dialog, int id) {
                       dialog.cancel();
                   }
               });
        final AlertDialog alert = builder.create();

        alert.show();
    }

}
6
ManicBlowfish

J'utilise une boîte de dialogue créée sur mesure. Il sera appelé par le service ou le gestionnaire même dans le cas où l'activité en cours perdrait le focus.

Activité de ma boîte de dialogue personnalisée :

public class AlertDialogue extends AppCompatActivity {

    Button btnOk;
    TextView textDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE); //comment this line if you need to show Title.
        setContentView(R.layout.activity_alert_dialogue);

        textDialog = (TextView)findViewById(R.id.text_dialog) ;
        textDialog.setText("Hello, I'm the dialog text!");

        btnOk = (Button) findViewById(R.id.button_dialog);
        btnOk.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

Vous pouvez appeler cette boîte de dialogue en utilisant:

Intent intent = new Intent(this, AlertDialogue.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Dans le manifeste :

<activity Android:name=".AlertDialogue"
    Android:theme="@style/AlertDialogMy">

</activity>

style:

<resources>

    <style name="AlertDialogMy" parent="Theme.AppCompat.Light.Dialog">
        <item name="Android:windowNoTitle">true</item> //delete this line if you need to show Title.
    </style>

</resources>

Voici le code complet de cette exemple .

4
V.March

Voici une implémentation qui permettra d'afficher un AlertDialog au-dessus de l'activité active en cours (ceci est un exemple de boîte de dialogue de message, mais peut également être utilisé pour les alertes).

public class AlertsDialogue
{
    private AlertDialog.Builder alertDialogBuilder;
    private AlertDialog alert;

    public AlertsDialogue(Context context, String title, String message)
    {
        alertDialogBuilder = new AlertDialog.Builder(context);
        alertDialogBuilder.setTitle(title);
        alertDialogBuilder.setIcon(R.drawable.ic_launcher);
        alertDialogBuilder.setMessage(message)
            .setCancelable(false)
            .setPositiveButton(context.getString(R.string.text_ok), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    alert.dismiss();
                }
            });

        alert = alertDialogBuilder.create();
        Window window = alert.getWindow();
        if (window != null)
        {
            // the important stuff..
            window.setType(WindowManager.LayoutParams.TYPE_TOAST);
            alert.show();
        }
        else
            Toast.makeText(context, message, Toast.LENGTH_LONG).show();
    }
}

La boîte de dialogue sera affichée même si le contexte sur lequel elle a été instanciée n'est plus actif, un peu comme Toast.

Appeler avec new AlertsDialogue(MyActivity.this, "title", "message");

Aucune autorisation supplémentaire n'est requise dans le fichier AndroidManifest.

1
Derorrist

Quel type de tâches réseau se déroule en arrière-plan. Je suggérerais éventuellement de repenser le design. Peut-être qu'une notification serait meilleure? Ou peut-être un écran "résumé des résultats". En tant qu'utilisateur, je préfère un signal d'erreur non intrusif si je n'attends pas activement la fin de la tâche.

0
px3j

vous devez réinitialiser le type de fenêtre auquel la boîte de dialogue est attachée, comme suit: dialog.getWindow (). setType (WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

n'oubliez pas de déclarer l'autorisation "Android.permission.SYSTEM_ALERT_WINDOW" dans votre manifeste.

0
hopetribe

Je suis également confronté au problème. Je trouve une solution simple et efficace. Habituellement, nous avons une activité de base utilisée pour gérer une logique commune. Ayez donc ceci:

public class BaseActionBarActivity extends ActionBarActivity{  //this BaseActionBarActivity is the Base Act

   private static BaseActionBarActivity current;

   @Override
   protected void onStart() {
     super.onStart();
     current=this;
   }


   public static BaseActionBarActivity getCurrentContext() {
     return current;
   }
}

le champ en cours est l'activité de contexte actuelle. Et je crois qu'il n'y a pas de question de fuite de mémoire. Ça marche bien pour moi! J'espère utile

0
Victor Choy

Pourquoi ne pas utiliser le bus d'événements ( https://github.com/greenrobot/EventBus )?

  1. Définissez les événements:

    public class ShowErrorMessageEvent {
    
        public String errorMessage;
    
        public ShowErrorMessageEvent(String errorMessage) {
            this.errorMessage = errorMessage;
        }
        public String getErrorMessage() {
            return this.errorMessage;
        }
    }
    
  2. Préparez les abonnés pour toutes les activités dont vous avez besoin:

    @Override
    public void onStart() { 
        super.onStart(); 
        EventBus.getDefault().register(this);
    }
    
    @Override
    public void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
    
  3. Dans toutes les activités, affichez la boîte de dialogue si l'événement a été reçu

     public void onEvent(ShowErrorMessageEvent event) {
         /* Show dialog with event.getErrorMessage() from background thread */
     };
    
  4. Dans votre fil d'arrière-plan, publiez l'événement d'erreur:

    EventBus.getDefault().post(new ShowErrorMessageEvent("This is an error message!"));
    
0
Allen Chan