48

以下のコードをご覧ください。

public class MyGridFragment extends Fragment{
    
    Handler myhandler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            switch (message.what) {
                case 2:   
                    ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
                    urls.addAll(theurls);
                    theimageAdapter.notifyDataSetChanged();
                    dismissBusyDialog();
                    break;
            }
        }
    }
}

このようなハンドラーを使用すると、「ハンドラーは静的である必要があります。そうしないと、メモリ リークが発生しやすくなります」という警告が表示されます。誰かがこれを行うための最良の方法を教えてもらえますか?

4

6 に答える 6

101

最近、自分のコードで似たようなものを更新しました。匿名のHandlerクラスを保護された内部クラスにしたところ、Lintの警告が消えました。以下のコードのようなものがあなたのために働くかどうか見てください:

public class MyGridFragment extends Fragment{

    static class MyInnerHandler extends Handler{
        WeakReference<MyGridFragment> mFrag;

        MyInnerHandler(MyGridFragment aFragment) {
            mFrag = new WeakReference<MyGridFragment>(aFragment);
        }

        @Override
        public void handleMessage(Message message) {
            MyGridFragment theFrag = mFrag.get();
            switch (message.what) {
            case 2:
                ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
                theFrag.urls.addAll(theurls);
                theFrag.theimageAdapter.notifyDataSetChanged();
                theFrag.dismissBusyDialog();
                break;
            }//end switch
        }
    }
    MyInnerHandler myHandler = new MyInnerHandler(this);
}

私が「theFrag」を置く場所を変更する必要があるかもしれません。私はそれらが何を参照しているかについてしか推測できなかったので。

于 2012-07-05T01:12:00.243 に答える
11

これは、私が作成した、あなたが使用できるやや便利な小さなクラスです。悲しいことに、匿名の静的内部クラスを持つことができないため、まだ非常に冗長です。

import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;

/** A handler which keeps a weak reference to a fragment. According to
 * Android's lint, references to Handlers can be kept around for a long
 * time - longer than Fragments for example. So we should use handlers
 * that don't have strong references to the things they are handling for.
 * 
 * You can use this class to more or less forget about that requirement.
 * Unfortunately you can have anonymous static inner classes, so it is a
 * little more verbose.
 * 
 * Example use:
 * 
 *  private static class MsgHandler extends WeakReferenceHandler<MyFragment>
 *  {
 *      public MsgHandler(MyFragment fragment) { super(fragment); }
 * 
 *      @Override
 *      public void handleMessage(MyFragment fragment, Message msg)
 *      {
 *          fragment.doStuff(msg.arg1);
 *      }
 *  }
 * 
 *  // ...
 *  MsgHandler handler = new MsgHandler(this);
 */
public abstract class WeakReferenceHandler<T> extends Handler
{
    private WeakReference<T> mReference;

    public WeakReferenceHandler(T reference)
    {
        mReference = new WeakReference<T>(reference);
    }

    @Override
    public void handleMessage(Message msg)
    {
        if (mReference.get() == null)
            return;
        handleMessage(mReference.get(), msg);
    }

    protected abstract void handleMessage(T reference, Message msg);
}
于 2012-11-21T12:52:59.517 に答える
5

ADT 20の変更によると、静的にする必要があるようです。

新しいリントチェック:

フラグメントクラスがインスタンス化可能であることを確認してください。誤ってフラグメント内部クラスを非静的にした場合、またはデフォルトのコンストラクターを忘れた場合、構成の変更後にシステムがフラグメントを再インスタンス化しようとすると、ランタイムエラーが発生する可能性があります。

ハンドラーリークを探す:このチェックは、ハンドラーの内部クラスがその外部クラスへの暗黙の参照を保持していないことを確認します。

于 2012-07-03T05:12:53.790 に答える
4

AccountManager または PendingIntent に関するドキュメントを読むと、いくつかのメソッドが Handler を引数の 1 つとして取ることがわかります。

:

  • onFinished - 送信が完了したときにコールバックするオブジェクト、またはコールバックがない場合は null。
  • handler -コールバックが発生するスレッドを識別するハンドラー。null の場合、コールバックはプロセスのスレッド プールから発生します。

状況を想像してください。一部のアクティビティは PendingIntent.send(...) を呼び出し、Handler の非静的内部サブクラスを置きます。そして、活動は破壊されます。しかし、インナークラスは生きています。

内部クラスには、破棄されたアクティビティへのリンクがまだ保持されているため、ガベージ コレクトできません。

ハンドラーをそのようなメソッドに送信する予定がない場合は、心配する必要はありません。

于 2012-07-03T12:10:43.420 に答える
0

同じ問題が発生しましたが、これはこのトピックの1つであり、多くの質問といくつかの回答があります。私の解決策は単純で、誰かに役立つことを願っています。

/* BEFORE */
private Handler mHandler= new Handler() {
        @Override public void handleMessage(Message msg) {
        this.doSomething();
    };
};

Runnableを実行するだけの静的Handlerサブクラスを作成できます。実際のハンドラーインスタンスは、インスタンス変数にアクセスできるランナブルを介して何をすべきかを知っています。

/* AFTER */
static class RunnableHandler extends Handler {
    private Runnable mRunnable;
    public RunnableHandler(Runnable runnable) { 
        mRunnable = runnable;
    }
    @Override public void handleMessage(Message msg) {
        mRunnable.run();
    };
}
private RunnableHandler mHandler = new RunnableHandler(new Runnable() {
    @Override public void run() {
        this.doSomething();
    } });

機能性は同じですが、警告は消えています。

于 2012-07-05T10:27:26.233 に答える