2012-03-17 16 views
28

Sembra che dovrebbe essere semplice, ma non trovo una risposta da nessuna parte. Ho un'applicazione Android che esegue attività di rete in background. Se ritorna un errore, voglio visualizzare una finestra di errore. Quando l'attività ritorna, non so quale attività è in primo piano. Basato su this post, sembra che non possiamo usare il contesto dell'applicazione per visualizzare una finestra di dialogo (e in effetti io prendo il crash se provo).Come faccio a visualizzare una finestra di dialogo in Android senza un contesto di attività?

Quindi, come posso ottenere il contesto dell'attività corrente? Di nuovo, il ricevitore per l'attività di rete è in esecuzione nel contesto dell'applicazione, non in una particolare attività. Altre idee?

Modifica: dovrei chiarire. Non voglio visualizzare una finestra di errore se non sono l'applicazione in primo piano. Mi interessa solo il caso in cui la nostra app è in primo piano per ora.

+0

È possibile utilizzare un [Toast] (http://developer.android.com/reference/android/widget/Toast.html). Afaik non c'è modo di visualizzare una finestra di dialogo senza l'app in primo piano attiva. – zapl

risposta

20

Se un errore torna, voglio visualizzare un messaggio di errore.

Si prega di farlo solo se si sa che l'utente sta utilizzando attivamente la propria applicazione. L'utente sarà molto seccato se li interromperà nel mezzo di qualcos'altro (giocando a un gioco, guardando un film, leggendo un libro).

Così come posso ottenere il contesto dell'attività in corso?

Non è così. Al massimo, lasci che l'attività corrente sappia che deve fare qualcosa.

Altre idee?

Una possibilità è quella di utilizzare una trasmissione ordinata, in modo se avete un'attività in primo piano, si ottiene il controllo, altrimenti si alza un Notification per consentire all'utente di conoscere il problema senza schioccare una finestra di dialogo. L'attività che riceve la trasmissione ordinata può visualizzare un AlertDialog o altrimenti consentire all'utente di conoscere il problema. Ho scritto sui dettagli su come fare questo in a blog post (e a book chapter, per quella materia) e here is a sample application dimostrando la tecnica.

Oppure chiamare il servizio startActivity() per avviare a dialog-themed activity.

+0

Se non ha un contesto, come può creare e far scattare una notifica? Una notifica richiede che venga creato un contesto? Ho un thread in background in esecuzione che non è associato a nessuna attività, quindi non ho modo di ottenere un contesto di attività per avviare la notifica in primo luogo. – AgentKnopf

+0

@Zainodis: "Sto eseguendo un thread in background che non è associato a nessuna attività" - questo è un bug. Dovresti averlo gestito da qualche componente, come un servizio. Quindi, il 'Servizio' è il tuo' Contesto' per seguire ciò che ho scritto nella mia risposta. – CommonsWare

+0

Grazie per il suggerimento - eravamo abituati ad avere un servizio per esso (il thread in background gestisce le connessioni del server) - poi siamo tornati ad un thread in background, perché occasionalmente il nostro servizio sarebbe stato ucciso (dal sistema operativo ipotizzato, dato che non c'erano eccezioni o simili per causare un fallimento improvviso) senza alcuna ragione apparente (che è un no-go nel nostro caso). – AgentKnopf

0

Che tipo di attività di rete sono in corso in background. Suggerirei di ripensare il design. Forse una notifica sarebbe meglio? O forse una schermata di "sintesi dei risultati". Come utente preferirei un segnale di errore non invadente se non sto aspettando attivamente che l'attività venga completata.

6

Ho creato una classe di supporto che implementa l'idea di CommonsWare. Le attività che desiderano visualizzare gli avvisi devono semplicemente chiamare Alerts.register() e Alerts.unregister(). Quindi chiunque può chiamare Alerts.displayError().

commenti benvenuto.

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

} 
+0

Ciao, Come uso questa classe, ho un problema con questo. cos'è Myapplication? – MRT

+0

MyApplication.INTENT_DISPLAYERROR è una costante, cosa che presumo sia, l'app di ManicBlowfish che rappresenta una stringa. Potresti sostituirlo con una stringa a tua scelta. – Jon

1

Ho anche affrontato il problema. Scopro una soluzione semplice ed efficace.Usuallay, abbiamo un'attività di base utilizzata per gestire una logica comune. Quindi:

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; 
    } 
} 

il campo corrente è l'attuale Context Actitvity. E credo che non ci siano domande sulla perdita di memoria. Funziona bene per me! Spero utile

0

Perché non utilizzare il bus eventi (https://github.com/greenrobot/EventBus)?

  1. definire gli eventi:

    public class ShowErrorMessageEvent { 
    
        public String errorMessage; 
    
        public ShowErrorMessageEvent(String errorMessage) { 
         this.errorMessage = errorMessage; 
        } 
        public String getErrorMessage() { 
         return this.errorMessage; 
        } 
    } 
    
  2. Preparare gli abbonati per tutte le attività che avete avuto bisogno:

    @Override 
    public void onStart() { 
        super.onStart(); 
        EventBus.getDefault().register(this); 
    } 
    
    @Override 
    public void onStop() { 
        EventBus.getDefault().unregister(this); 
        super.onStop(); 
    } 
    
  3. In tutte le attività, visualizzare la finestra se l'evento ha ricevuto

    public void onEvent(ShowErrorMessageEvent event) { 
        /* Show dialog with event.getErrorMessage() from background thread */ 
    }; 
    
  4. Nel vostro thread in background, inviare l'evento di errore:

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

è necessario ripristinare il tipo di finestra che dialogo attaccato, come segue:. dialog.getWindow() setType (WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

non dimenticare di dichiarare l'autorizzazione "android.permission.SYSTEM_ALERT_WINDOW" nel tuo manifest.

1

Ecco un'implementazione che consentirà di visualizzare un AlertDialog sopra l'attività attiva corrente (questo è un esempio di finestra di dialogo di un messaggio, ma può essere utilizzato anche per gli avvisi).

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 finestra di dialogo viene visualizzato anche se il contesto in cui è stato istanziato con non è più attivo, molto simile Toast.

chiamata con new AlertsDialogue(MyActivity.this, "title", "message");

Nessun autorizzazioni aggiuntive sono necessarie nel file AndroidManifest.

Problemi correlati