310

サービスを使用して Android 2.3.3 アプリケーションを開発しています。メインアクティビティと通信するために、そのサービス内にこれがあります:

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

ここでfinal Messenger mMessenger = new Messenger(new IncomingHandler());、次の Lint 警告が表示されます。

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

どういう意味ですか?

4

7 に答える 7

398

IncomingHandlerクラスが静的でない場合、Serviceオブジェクトへの参照があります。

Handler同じスレッドのオブジェクトはすべて共通の Looper オブジェクトを共有し、メッセージを投稿したり読み取ったりします。

メッセージには target が含まれHandlerているため、メッセージ キューにターゲット ハンドラーを持つメッセージがある限り、ハンドラーはガベージ コレクションの対象になりません。ハンドラーが静的でない場合、破棄された後でも、ServiceまたはActivityをガベージ コレクションすることはできません。

これにより、メッセージがキューに残っている限り、少なくともしばらくの間、メモリ リークが発生する可能性があります。長い遅延メッセージを投稿しない限り、これは大きな問題ではありません。

IncomingHandler静的にしてWeakReference、サービスに次のように設定できます。

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

詳細については、Romain Guy によるこの投稿を参照してください。

于 2012-07-10T07:13:38.647 に答える
73

他の人が言及しているように、Lint 警告はメモリ リークの可能性があるためです。Handler.Callback構築時にa を渡すことで、Lint 警告を回避できHandlerます (つまり、サブクラス化せず、非静的内部クラスHandlerがありません)。Handler

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

私が理解しているように、これは潜在的なメモリリークを回避しません。Messageオブジェクトは、参照をmIncomingHandler保持するオブジェクトへの参照Handler.Callbackを保持します オブジェクトへの参照を保持するServiceオブジェクト。Looperメッセージ キューにメッセージがある限り、ServiceGC は行われません。ただし、メッセージ キューに長い遅延メッセージがない限り、深刻な問題にはなりません。

于 2013-02-11T00:55:56.540 に答える
33

以下は、弱参照と静的ハンドラー クラスを使用して問題を解決する一般的な例です (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);
  }
}
于 2015-01-07T18:25:07.773 に答える
27

この方法は私にとってはうまくいきました。メッセージを処理する場所を独自の内部クラスに保つことで、コードをきれいに保ちます。

使用したいハンドラー

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

内部クラス

class IncomingHandlerCallback implements Handler.Callback{

        @Override
        public boolean handleMessage(Message message) {

            // Handle message code

            return true;
        }
}
于 2013-04-17T23:16:47.073 に答える
0

よくわかりません。私が見つけた例では、静的プロパティを完全に回避し、UI スレッドを使用しています。

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

このソリューションで私が気に入っているのは、クラス変数とメソッド変数を混在させようとしても問題がないことです。

于 2020-01-10T03:46:04.780 に答える