【问题标题】:Message Handlers and the WeakReference issue消息处理程序和弱引用问题
【发布时间】:2012-10-16 22:57:33
【问题描述】:

以下消息处理程序可以正常接收来自我的服务的消息...

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 中测试正常(我通过 DDMS 向它提供了一个大的 KML 文件)“对象路径 = message.obj;”行有一个警告说“这个处理程序类应该是静态的,否则可能会发生泄漏”。

但如果我说“静态 Handler handler = new Handler()”,它不会编译并抱怨我“不能对非静态字段 myMapView 进行静态引用。如果我不能进行这样的引用,我可以'不要做任何有用的事情。

这让我花了几个小时在谷歌上搜索这个问题,并了解了比我想知道的更多关于弱引用的信息。我发现经常发现的建议是我应该替换...

private Handler handler = new Handler()

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

但这不会编译仍然抱怨我无法对非 dtatic 字段进行静态引用。所以,我一周或之前的问题是“我怎样才能为 android 编写一个消息处理程序,以便我的服务可以将数据发送到我的活动。即使我有工作代码,问题仍然与后缀“不泄漏内存”有关。 谢谢,加里

【问题讨论】:

    标签: android memory-leaks android-handler


    【解决方案1】:

    当我尝试在服务中使用处理程序时,我收到了相同的警告消息,最后通过接受this thread 的建议解决了这个问题,请参阅我项目中的代码 sn-p。

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

    【讨论】:

    • 看起来你没有引用任何非静态对象,所以你会没事的。我正在做这样的参考。现在我已将 myMapview 和控制器设为静态,但我可能并不总是能够做到这一点。试着做一个这样的参考,看看你会得到什么。
    • 我看到 message.obj 是一个字符串,如果它不是太长那么你可以忽略警告(路径的长度通常在 256 以内,所以它最多消耗半公斤-字节,假设您有 100 条消息在队列中,那么处理程序持有 50kB,可忽略)。如果您有充分的理由担心潜在的内存泄漏,那么当您收到消息时,您可以首先为 obj 分配一个弱引用“msg.obj = new WeakReference(path);”,然后在使用前的 handleMessage 检查 "WeakReference ref = message.obj; String str = ref.get(); if (str!=null) ..."
    【解决方案2】:

    我知道我参加聚会有点晚了,但希望这有助于进一步回答未来询问者的问题。

    正如您通过谷歌搜索发现的那样(我自己做了很多事情来解决类似的问题),您需要将 Handler 实例转换为静态内部类(嵌套类),该类在其构造函数中采用目标 Activity .然后它将这个 Activity 引用转换为 WeakReference,这就是可以用来与目标 Activity 中的事物交互的东西。在你的情况下:

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

    由于您要更改为嵌套类,您还需要创建该类的实例,以便您的线程在其 run() 方法中访问。有关这方面的更多帮助(以及如何确保您的应用即使在配置更改后也能正常工作)请参阅this question

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      相关资源
      最近更新 更多