Обработчики сообщений и проблема WeakReference

Обработчик следующего сообщения отлично работает, получая сообщения от моей службы...

private  Handler handler = new Handler() 
{

    public void handleMessage(Message message) 
    {
        Object path = message.obj;

        if (message.arg1 == 5 && path != null)  //5 means its a single mapleg to plot on the map
        {
            String myString = (String) message.obj;
            Gson gson = new Gson();
            MapPlot mapleg = gson.fromJson(myString, MapPlot.class);
            myMapView.getOverlays().add(new DirectionPathOverlay(mapleg.fromPoint, mapleg.toPoint));
            mc.animateTo(mapleg.toPoint);

        }
        else
        {
            if (message.arg1 == RESULT_OK && path != null) 
            {
                Toast.makeText(PSActivity.this, "Service Started" + path.toString(), Toast.LENGTH_LONG).show();
            } 
            else 
            {
                Toast.makeText(PSActivity.this,"Service error" + String.valueOf(message.arg1),  Toast.LENGTH_LONG).show();          


            }

        }
    };
};

Однако, несмотря на то, что он хорошо проверяется в AVD (я передаю ему большой файл KML через DDMS), «путь к объекту = message.obj;» В строке есть ПРЕДУПРЕЖДЕНИЕ о том, что «этот класс Handler должен быть статическим, иначе могут возникнуть утечки».

Но если я скажу «статический обработчик обработчика = новый обработчик ()», он не будет компилироваться, жалуясь, что я «не могу сделать статическую ссылку на нестатическое поле myMapView. Если я не могу сделать такие ссылки, я не могу сделать ничего полезного.

Это привело к тому, что я потратил несколько часов на гугление по этой проблеме и узнал о weakReferences больше, чем я когда-либо хотел знать. Часто встречающаяся рекомендация, которую я нахожу, заключается в том, что я должен заменить ...

private Handler handler = new Handler()

с участием

   static class handler extends Handler
{
    private final WeakReference<PSActivity> mTarget;
    handler(PSActivity target)
    {
        mTarget = new WeakReference<PSActivity>(target);
    }

Но это не будет компилироваться, все еще жалуясь, что я не могу сделать статическую ссылку на нестатическое поле. Итак, мой вопрос неделю назад был: «Как я могу написать обработчик сообщений для Android, чтобы моя служба могла отправлять данные в мою деятельность. Несмотря на то, что у меня есть рабочий код, вопрос остается с суффиксом «без утечки памяти». Спасибо, Гэри


person Dean Blakely    schedule 16.10.2012    source источник


Ответы (2)


Я получил такое же предупреждающее сообщение, когда попытался использовать обработчик в службе, и, наконец, разрешил его, воспользовавшись советом этот поток, см. фрагмент кода из моего проекта.

public class MyService extends Service {
    ...
    private MyHandler mHandler;

    public static class MyHandler extends Handler {
        private final WeakReference<MyService> mService;

        MyHandler(MyService service) {
            mService = new WeakReference<MyService>(service);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            MyService service = mService.get();
            if (service!=null) {
                if (msg.what==MSG_RESUME_CHECKING) {
                    service.pause();
                } else if (msg.what==MSG_PAUSE_CHECKING) {
                    service.resume();
                }
            }
        }
    }
    ...

    @Override
    public void onCreate() {
        super.onCreate();
        ...
        mHandler = new MyHandler(this);
        ...
    }
}
person Ziteng Chen    schedule 17.10.2012
comment
Не похоже, что вы ссылаетесь на какие-либо нестатические объекты, так что все будет в порядке. Я делаю такую ​​ссылку. На данный момент я сделал myMapview и контроллер статическими, но я не всегда могу это сделать. Попробуйте сделать такую ​​ссылку и посмотрите, что у вас получится. - person Dean Blakely; 18.10.2012
comment
Как я вижу, message.obj - это строка, если она не слишком длинная, вы можете игнорировать предупреждение (длина пути обычно не превышает 256, поэтому он потребляет не более полукилобайта, предположим, что у вас есть 100 сообщений в очереди, то обработчик удерживает 50 КБ, пренебрежимо мало). Если у вас есть веская причина беспокоиться о потенциальной утечке памяти, то, когда вы получите сообщение, вы можете назначить слабую ссылку на объект в первую очередь msg.obj = new WeakReference‹String›(path); и в handleMessage проверьте перед использованием WeakReference‹String› ref = message.obj; Строка ул = ref.get(); если (str!=null) ... - person Ziteng Chen; 18.10.2012

Я знаю, что немного опоздал на вечеринку, но, надеюсь, это поможет ответить на вопрос для будущих исследователей.

Как вы обнаружили в своем поиске в Google (что-то, что я сделал сам для решения аналогичной проблемы), вам нужно превратить ваш экземпляр Handler в статический внутренний класс (вложенный класс), который принимает целевую активность в своем конструкторе. Затем он преобразует эту ссылку Activity в WeakReference, и это то, что можно использовать для взаимодействия с вещами в вашей целевой Activity. В твоем случае:

Toast.makeText(mTarget.get().this, "Service Started" + path.toString(), Toast.LENGTH_LONG).show();

Поскольку вы переходите на вложенный класс, вам также необходимо создать экземпляр этого класса, чтобы ваш поток мог получить доступ к его методу run(). Для получения дополнительной помощи по этому вопросу (а также о том, как убедиться, что ваше приложение работает даже после изменений конфигурации), см. this вопрос.

Надеюсь это поможет!

person George    schedule 23.10.2014