2014-12-08 19 views
10

UPDATE: Non sono d'accordo che si tratta di un duplicato - perché sto cercando un modo per uscire dall'app principale e mostrare ancora un Toast dal servizio.Come visualizzare Toast da un servizio al termine dell'attività principale?

In a very simple test app Ho 2 pulsanti:

screenshot

Cliccando qualsiasi dei pulsanti verrà eseguito un servizio con una stringa azione corrispondente ("aperto" o "flash") -

OpenActivity.java:

public class OpenActivity extends Activity { 
    private Intent mServiceIntent; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_open); 
     mServiceIntent = new Intent(this, RegionService.class); 
    } 

    public void openCar(View v) { 
     mServiceIntent.setAction("open"); 
     startService(mServiceIntent); 
    } 

RegionService.java:

public class RegionService extends IntentService { 
    private static final String TAG = "RegionService"; 

    @Override 
    protected void onHandleIntent(Intent intent) { 
     Log.d(TAG, "Received an intent: " + intent); 
     String action = intent.getAction(); 
     Log.d(TAG, "Received an action: " + action); 

     if(action.equals("open")) { 
      Toast.makeText(this, 
        getString(R.string.car_opened), 
        Toast.LENGTH_SHORT).show(); 
     } 

Purtroppo la mia applicazione si blocca con:

D/RegionService(24506): Received an intent: Intent { act=open cmp=de.afarber.mynotification/.RegionService } 

D/RegionService(24506): Received an action: open 

W/MessageQueue(24506): Handler (android.os.Handler) {422768a8} sending message to a Handler on a dead thread 
W/MessageQueue(24506): java.lang.RuntimeException: Handler (android.os.Handler) {422768a8} sending message to a Handler on a dead thread 
W/MessageQueue(24506): at android.os.MessageQueue.enqueueMessage(MessageQueue.java:320) 
W/MessageQueue(24506): at android.os.Handler.enqueueMessage(Handler.java:626) 
W/MessageQueue(24506): at android.os.Handler.sendMessageAtTime(Handler.java:595) 
W/MessageQueue(24506): at android.os.Handler.sendMessageDelayed(Handler.java:566) 
W/MessageQueue(24506): at android.os.Handler.post(Handler.java:326) 
W/MessageQueue(24506): at android.widget.Toast$TN.hide(Toast.java:370) 
W/MessageQueue(24506): at android.app.ITransientNotification$Stub.onTransact(ITransientNotification.java:54) 
W/MessageQueue(24506): at android.os.Binder.execTransact(Binder.java:412) 
W/MessageQueue(24506): at dalvik.system.NativeStart.run(Native Method) 

Essendo un novizio di programmazione Android Mi chiedo Come visualizzare un Toast da servizio in modo corretto?

Penso di aver già visto Toasts in Android Home (cioè non c'erano attività sullo schermo del dispositivo e c'erano ancora Toasts).

Il mio background: Vorrei monitorare un dispositivo faro dal mio servizio e mostrare alcuni testo Brindisi - anche quando la mia applicazione è stata chiusa.

+0

http://www.jjoe64.com/2011/09/ show-toast-notification-from-service.html – Suvitruf

+0

possibile duplicato di [Toast creato in un IntentService non scompare mai] (http://stackoverflow.com/questions/3296639/toast-created-in-an-intentservice-never- va via) –

+0

Non sono d'accordo che questo è un duplicato - perché nel mio caso mi piacerebbe uscire dall'app principale e mostrare ancora un Toast dal servizio. –

risposta

22

OnHandleIntent verrà eseguito in un differant Thread modo si sta mostrando Toast in un thread che non è consentita in Android

quindi modificare il codice come questo

Handler handler = new Handler(Looper.getMainLooper()); 
handler.post(new Runnable() { 

    @Override 
    public void run() { 
     Toast.makeText(getApplicationContext(), 
         getString(R.string.car_opened), 
         Toast.LENGTH_SHORT).show();    
    } 
}); 

Da questo dead thread in service

IntentService creerà un thread per gestire il nuovo intento e lo ha terminato immediatamente dopo che l'attività è stata eseguita. Quindi, il Toast sarà fuori controllo da un thread morto.

Si dovrebbero vedere alcune eccezioni nella console quando il pane tostato viene visualizzato sullo schermo.

+0

Ho provato a inserire il codice in [onHandleIntent] (https://github.com/afarber/android-newbie/blob/q12/MyNotification/src/de/afarber/mynotification/RegionService.java) - ma lo fa non compilare a causa di ** questo ** essendo un 'Runnable'. –

+1

@AlexanderFarber posiziona YourService.this anziché this o chaneg per getApplicationContext() –

+1

@AlexanderFarber modifica modificata come quella –

1

utilizzare il seguente codice:

runOnUiThread(new Runnable(){ 
    public void run() { 
      // UI code goes here 
    } 
    }); 
+0

sì mostra anche quando il servizio è in esecuzione in background – TechHelper

+0

'runOnUiThread' è disponibile solo in un'attività, no? –

+0

L'istanza dell'attività può essere passata a un servizio – TechHelper

2

OnHandleIntent viene chiamato su un thread in background, e qualsiasi tentativo di toccare l'interfaccia utente si tradurrà in un incidente. Usa un gestore per pubblicare un Runnable sul thread dell'interfaccia utente per mostrare il tuo brindisi.

private class MyRunnable implements Runnable { 

    final int mTextId = -1; 
    final Context mContext; 
    public MyRunnable(Context c, int textId) { 
     mTextId = textId; 
     mContext = c; 
    } 

    @Override 
    public void run() { 
     Toast.makeText(mContext, 
      getString(mTextId), 
      Toast.LENGTH_SHORT).show();    
    } 
} 

    Handler handler = new Handler(); 
    handler.post(new MyRunnable(this, R.string.car_opened)); 
+0

Funzionerà anche quando esco dall'app principale? –

+1

Perché non provi tutti questi frammenti di codice? :) –

+0

Certo che provo i frammenti, ma a volte bug/arresti anomali non sono immediatamente visibili (specialmente quando qualcosa viene eseguito in background) - ecco perché è bene chiedere. –

5

Un IntentService ha alcune limitazioni:

non può interagire direttamente con l'interfaccia utente. Per inserire i suoi risultati nell'interfaccia utente, devi inviarli a un'attività.

Tutto sta accadendo nel thread in background e non sul thread UI, quindi è necessario un modo diverso, come illustrato di seguito:

@Override 
public void onCreate() { 
    super.onCreate(); 
    mHandler = new Handler(); 
} 

@Override 
protected void onHandleIntent(Intent intent) { 
    mHandler.post(new Runnable() {    
     @Override 
     public void run() { 
      Toast.makeText(MyIntentService.this, "Hello Toast!", Toast.LENGTH_LONG).show();     
     } 
    }); 
} 

Fonte: Toast created in an IntentService never goes away

0

Questo problema a causa di non correre il Toast dal main_thread e per ovviare a questo, durante la creazione dell'attività Salva il suo contesto dal metodo onCreate():

public static Context ctx; 

// the method responsible for running the MainActivity 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     ctx = this; 
} 

poi, nel servizio di aggiungere un gestore ed eseguire un filo da esso (come il gestore viene eseguito attraverso il filo principale):

Handler handler = new Handler(Looper.getMainLooper()); 
    handler.post(new Runnable() { 
     @Override 
     public void run() { 
      Toast.makeText(OpenActivity.ctx, getString(R.string.car_opened), 
        Toast.LENGTH_SHORT).show(); 
     } 
    }); 
+0

perché è necessario archiviare 'this'? –

+0

È una buona idea memorizzare un contesto in una variabile statica? –

+0

@LittleChild dato che non conosco lo stato Thread del suo servizio e non ho una panoramica della struttura e dei thread dell'applicazione, non salvandolo per lo più funzionerà ma in alcuni casi no, quindi l'ho salvato per assicurarmi che Certamente funzionerà. –