Ta klasa obsługi powinna być statyczna lub mogą wystąpić nieszczelności: IncomingHandler

[3]}rozwijam aplikację na Androida 2.3.3 z usługą. Mam to wewnątrz tego serwisu, aby komunikować się z główną działalnością:

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

I tutaj, final Messenger mMessenger = new Messenger(new IncomingHandler());, dostaję następujące ostrzeżenie Lint:

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

Co to znaczy?
Author: Dheeraj Vepakomma, 2012-07-10

7 answers

Jeśli IncomingHandler klasa nie jest statyczna, będzie miała odniesienie do twojego Service obiektu.

Handler wszystkie obiekty dla tego samego wątku mają wspólny obiekt Looper, do którego wysyłają i odczytują wiadomości.

Ponieważ wiadomości zawierają obiekt docelowy Handler, tak długo jak w kolejce wiadomości znajdują się wiadomości z obsługą celu, nie można ich usunąć. Jeśli funkcja obsługi nie jest statyczna, Twoje Service lub Activity nie mogą być zbierane, nawet po zniszczeniu.

Może to prowadzić do pamięć przecieka, przynajmniej przez jakiś czas - tak długo, jak wiadomości pozostają w kolejce. Nie jest to duży problem, chyba że publikujesz długo opóźnione wiadomości.

Możesz zrobić IncomingHandler statyczne i mieć WeakReference do swojego serwisu:

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);
         }
    }
}
W tej chwili możesz przypisać do domeny hosting, wybierając usługę dostosowaną do Twoich potrzeb:]}
 394
Author: Tomasz Niedabylski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-20 18:47:25

Jak inni wspominali, Ostrzeżenie Lint jest spowodowane potencjalnym wyciekiem pamięci. Możesz uniknąć ostrzeżenia Lint przekazując Handler.Callback podczas konstruowania Handler (tzn. nie podklasujesz Handler i nie ma Handler niestatycznej klasy wewnętrznej):

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

Jak rozumiem, nie uniknie to potencjalnego wycieku pamięci. Message obiekty przechowują odniesienie do mIncomingHandler obiektu, który przechowuje odniesienie Handler.Callback obiektu, który przechowuje odniesienie do Service obiektu. Dopóki są wiadomości w kolejce komunikatów Looper, Service nie będzie GC. Nie będzie to jednak poważny problem, jeśli w kolejce wiadomości nie będą wyświetlane komunikaty o dużym opóźnieniu.

 70
Author: Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-20 16:39:38

Oto ogólny przykład użycia słabej klasy referencji i statycznej obsługi do rozwiązania problemu (zgodnie z zaleceniami w dokumentacji Lint):

public class MyClass{

  //static inner class doesn't hold an implicit reference to the outer class
  private static class MyHandler extends Handler {
    //Using a weak reference means you won't prevent garbage collection
    private final WeakReference<MyClass> myClassWeakReference; 

    public MyHandler(MyClass myClassInstance) {
      myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
    }

    @Override
    public void handleMessage(Message msg) {
      MyClass myClass = myClassWeakReference.get();
      if (myClass != null) {
        ...do work here...
      }
    }
  }

  /**
   * An example getter to provide it to some external class
   * or just use 'new MyHandler(this)' if you are using it internally.
   * If you only use it internally you might even want it as final member:
   * private final MyHandler mHandler = new MyHandler(this);
   */
  public Handler getHandler() {
    return new MyHandler(this);
  }
}
 33
Author: Sogger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-26 14:47:07

Ten sposób zadziałał dobrze dla mnie, utrzymuje kod w czystości, utrzymując miejsce obsługi wiadomości we własnej klasie wewnętrznej.

Uchwyt, którego chcesz użyć

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

Klasa wewnętrzna

class IncomingHandlerCallback implements Handler.Callback{

        @Override
        public boolean handleMessage(Message message) {

            // Handle message code

            return true;
        }
}
 25
Author: Stuart Campbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-09 01:58:51

Z Pomocą odpowiedzi @Sogger stworzyłem ogólny Handler:

public class MainThreadHandler<T extends MessageHandler> extends Handler {

    private final WeakReference<T> mInstance;

    public MainThreadHandler(T clazz) {
        // Remove the following line to use the current thread.
        super(Looper.getMainLooper());
        mInstance = new WeakReference<>(clazz);
    }

    @Override
    public void handleMessage(Message msg) {
        T clazz = mInstance.get();
        if (clazz != null) {
            clazz.handleMessage(msg);
        }
    }
}

Interfejs:

public interface MessageHandler {

    void handleMessage(Message msg);

}

Używam go w następujący sposób. Ale nie jestem w 100% pewien, czy to jest bezpieczne. Może ktoś mógłby to skomentować:

public class MyClass implements MessageHandler {

    private static final int DO_IT_MSG = 123;

    private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);

    private void start() {
        // Do it in 5 seconds.
        mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case DO_IT_MSG:
                doIt();
                break;
        }
    }

    ...

}
 2
Author: Marius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-27 13:40:04

Nie jestem pewien, ale możesz spróbować wprowadzić handler do null w onDestroy ()

 0
Author: Chaitanya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-07 09:25:08

Jestem zdezorientowany. Przykład, który znalazłem, całkowicie unika właściwości statycznej i używa wątku interfejsu użytkownika:

    public class example extends Activity {
        final int HANDLE_FIX_SCREEN = 1000;
        public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                int imsg;
                imsg = msg.what;
                if (imsg == HANDLE_FIX_SCREEN) {
                    doSomething();
                }
            }
        };
    }

Rzecz, którą lubię w tym rozwiązaniu, to to, że nie ma problemu z mieszaniem zmiennych klasy i metody.

 0
Author: user2515235,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-10 03:46:04