2011-10-06 8 views
6

Sto facendo un servizio Android che fornisce contenuti ad altre app che possono registrarsi come callback.Assicurarsi che il mio codice sia sicuro per thread

Non sono sicuro al 100% su come funziona la classe Android Handler, quindi qualcuno può confermarmi che questo codice è sicuro?

public class MyService extends Service { 
    private static final String MESSAGE = "message"; 

    private final RemoteCallbackList<IMyCallback> readerCallbacks = new RemoteCallbackList<IMyCallback>(); 

    private static final int REPORT_MSG = 1; 

    private Thread readerThread; 

    @Override 
    public void onCreate() { 

     readerThread = new Thread(readerRunnable); 
     readerThread.setDaemon(true); 
     readerThread.start(); 

    } 

    private Runnable readerRunnable = new Runnable() { 
     @Override 
     public void run() { 
      while (!Thread.interrupted()) { 

       // Blocking call 
       byte[] message = JniCommunicator.readMessage(); 

       if (message == null || message.length == 0) { 
        continue; 
       } 

       Bundle b = new Bundle(); 
       b.putByteArray(MESSAGE, message); 
       Message m = readHandler.obtainMessage(REPORT_MSG); 
       m.setData(b); 
       readHandler.sendMessage(m); 
      } 
     } 
    }; 

    private final Handler readHandler = new Handler() { 
     @Override 
     public void handleMessage(Message msg) { 

      switch (msg.what) { 
      case REPORT_MSG: 

       byte[] message = msg.getData().getByteArray(MESSAGE); 

       // Broadcast the new message to all clients 
       final int N = readerCallbacks.beginBroadcast(); 
       for (int i = 0; i < N; i++) { 
        try { 
         readerCallbacks.getBroadcastItem(i).newMessage(message); 
        } catch (RemoteException e) { 
         // The RemoteCallbackList will take care of removing 
         // the dead object for us. 
        } 
       } 
       readerCallbacks.finishBroadcast(); 

       break; 
      } 
     } 
    }; 

     @Override 
    public IBinder onBind(Intent intent) { 
     return mBinder; 
    } 

    private final IService.Stub mBinder = new IService.Stub() { 

     public void registerCallback(IMyCallback cb) { 
      if (cb != null) 
       readerCallbacks.register(cb); 
     } 

     public void unregisterCallback(IMyCallback cb) { 
      if (cb != null) 
       readerCallbacks.unregister(cb); 
     } 
    }; 
} 

In particolare, se qualcuno chiama unregisterCallback(), mentre il gestore è nel ciclo for, sarà in crash?

Dalla mia comprensione, l'Handler si esegue nello stesso thread, quindi è thread-safe, ma non sono sicuro.

Grazie

+2

Dovrebbe essere acceso: http://codereview.stackexchange.com/ –

risposta

5

Handlers sono sicuri filo, cioè tutto il loro scopo.
Concordo sul fatto che la documentazione sulla sicurezza dei thread dei gestori non è la migliore, ma sarebbe molto ironico se una classe progettata per comunicare tra thread non fosse thread-safe.

chi callback remote, sono studiati anche per essere sicuri discussione, si dovrebbe leggere the documentation su questo, si afferma chiaramente:

Esegue bloccaggio della lista sottostante interfacce per trattare chiamate entranti multithread, e un modo thread-safe per iterare su un'istantanea della lista senza tenere il suo blocco

Tutto quello che devi fare è che tutte le variabili di accesso a più thread sono thread-safe (che sono nel tuo caso) e che non sono essere cambiato (i tuoi sono definitivi quindi non preoccuparti)

+0

Grazie. Ho anche scoperto che [beginBroadcast()] (http://developer.android.com/reference/android/os/RemoteCallbackList.html#beginBroadcast()) crea una copia dell'elenco, quindi va bene. – Jonas

+0

Puntelli su come pensare alla sicurezza dei thread, è piuttosto la giungla e partire presto è sempre buono :) –