317 votes

Cette classe Handler doit être statique ou des fuites peuvent survenir: IncomingHandler

Je développe une application Android 2.3.3 avec un service. J'ai ceci à l'intérieur de ce service pour communiquer avec l'activité principale:

 public class UDPListenerService extends Service
{
    private static final String TAG = "UDPListenerService";
    //private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
    private UDPListenerThread myThread;
    /**
     * Handler to communicate from WorkerThread to service.
     */
    private Handler mServiceHandler;

    // Used to receive messages from the Activity
    final Messenger inMessenger = new Messenger(new IncomingHandler());
    // Use to send message to the Activity
    private Messenger outMessenger;

    class IncomingHandler extends Handler
    {
        @Override
        public void handleMessage(Message msg)
        {
        }
    }

    /**
     * Target we publish for clients to send messages to Incoming Handler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());
    [ ... ]
}
 

Et ici, final Messenger mMessenger = new Messenger(new IncomingHandler()); , j'obtiens l'avertissement de Lint suivant:

This Handler class should be static or leaks might occur: IncomingHandler

Qu'est-ce que ça veut dire?

401voto

Tomasz Niedabylski Points 3198

Si IncomingHandler classe n'est pas statique, elle aura une référence à votre Service objet.

Handler objets pour le même thread tous partagent un Looper objet, qui de poster des messages et de la lecture.

Comme les messages contiennent cible Handler, tant qu'il y a des messages à la cible de gestionnaire dans la file d'attente de messages, le gestionnaire ne peut pas être nettoyée. Si le gestionnaire n'est pas statique, votre Service ou Activity ne peut pas être nettoyée, même après avoir été détruit.

Cela peut conduire à des fuites de mémoire, pour quelque temps du moins, tant que les messages restent int la file d'attente. Ce n'est pas vraiment un problème, à moins que vous publiez, longtemps retardée, messages.

Vous pouvez faire IncomingHandler statique et ont un WeakReference à votre service:

static class IncomingHandler extends Handler {
    private final WeakReference<UDPListenerService> mService; 

    IncomingHandler(UDPListenerService service) {
        mService = new WeakReference<UDPListenerService>(service);
    }
    @Override
    public void handleMessage(Message msg)
    {
         UDPListenerService service = mService.get();
         if (service != null) {
              service.handleMessage(msg);
         }
    }
}

Voir ce post par Romain Guy pour de plus amples référence

73voto

Michael Points 193

Comme d'autres l'ont mentionné les Peluches d'avertissement est en raison du risque de fuite de mémoire. Vous pouvez éviter les Peluches avertissement par le passage d'un Handler.Callback lors de la construction d' Handler (c'est à dire que vous n'avez pas de sous-classe Handler et il n'y a pas d' Handler non-statique à l'intérieur de la classe):

Handler mIncomingHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
    }
});

Si je comprends bien, ce ne sera pas éviter le risque de fuite de mémoire. Message objets contiennent une référence à l' mIncomingHandler objet qui contient une référence à l' Handler.Callback objet qui contient une référence à l' Service objet. Tant qu'il y a des messages dans l' Looper message de la file d'attente, Service ne sera pas en GC. Toutefois, il ne sera pas un problème grave, sauf si vous avez long délai d'attente de messages dans la file d'attente de messages.

27voto

Stuart Campbell Points 121

Cette façon de travailler a bien fonctionné pour moi, maintient le code propre en gardant où vous gérez le message dans sa propre classe interne.

Le gestionnaire que vous souhaitez utiliser

 Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());
 

La classe intérieure

 class IncomingHandlerCallback implements Handler.Callback{

    @Override
    public boolean handleMessage(Message message) {

        // Handle message code

        return true;
    }
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X