This Handler class should be static or leaks might occur Android

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介:

首先解释下这句话This Handler class should be static or leaks might occur,大致意思就是说:Handler类应该定义成静态类,否则可能导致内存泄露。

具体如何解决,在国外有人提出,如下:

Issue: Ensures that Handler classes do not hold on to a reference to an outer class

In Android, Handler classes should be static or leaks might occur. Messages enqueued on the application thread's MessageQueue also retain their target Handler. If the Handler is an inner class, its outer class will be retained as well. To avoid leaking the outer class, declare the Handler as a static nested class with a WeakReference to its outer class. 

大体翻译如下:

Handler 类应该应该为static类型,否则有可能造成泄露。在程序消息队列中排队的消息保持了对目标Handler类的应用。如果Handler是个内部类,那 么它也会保持它所在的外部类的引用。为了避免泄露这个外部类,应该将Handler声明为static嵌套类,并且使用对外部类的弱应用。

使用范例:

   

  1. static class MyHandler extends Handler {
  2.                 WeakReference<PopupActivity> mActivity;
  3.    
  4.                 MyHandler(PopupActivity activity) {
  5.                         mActivity = new WeakReference<PopupActivity>(activity);
  6.                 }
  7.    
  8.                 @Override
  9.                 public void handleMessage(Message msg) {
  10.                         PopupActivity theActivity = mActivity.get();
  11.                         switch (msg.what) {
  12.                         case 0:
  13.                                 theActivity.popPlay.setChecked(true);
  14.                                 break;
  15.                         }
  16.                 }
  17.         };
  18.    
  19.         MyHandler ttsHandler = new MyHandler(this);
  20.         private Cursor mCursor;
  21.    
  22.         private void test() {
  23.                 ttsHandler.sendEmptyMessage(0);
  24.         }

原文:http://www.cnblogs.com/savagemorgan/archive/2013/01/23/2872371.html

疑问:是否有其它解决方法?

这个提示就是由于Handler的直接引用会导致相关的Activity、Service等无法被GC。如果这么弱应用的话,会出现空指针,有其它解决方法?

抽时间研究下。

   

 ==================================================================================================================================

 原始代码:

  1. public class MainActivity extends Activity {
  2.  
  3.    private static int urlIndex = 0;
  4.    private final static String TAG = MainActivity.class.getSimpleName();
  5.    private static final String[] url = {
  6.          "http://vdn.apps.cntv.cn/api/getLiveUrlCommonRedirectApi.do?channel=pa://cctv_p2p_hdcctv1&type=ipad",
  7.          "http://74.82.62.53:1935/liverepeater/13.stream/playlist.m3u8", "http://rtmp.cntv.lxdns.com/live/cctv3/playlist.m3u8", };
  8.  
  9.    private static final int MSG_PLAY = 100;
  10.    private static final int MSG_RUN_ADB = 101;
  11.    Handler playHandler = new Handler() {
  12.       @Override
  13.       public void handleMessage(Message msg) {
  14.          switch (msg.what) {
  15.          case MSG_PLAY:
  16.             urlIndex = urlIndex > url.length - 1 ? 0 : urlIndex;
  17.             videoView.setVideoPath(url[urlIndex]);
  18.             ++urlIndex;
  19.             break;
  20.          case MSG_RUN_ADB:
  21.             killMediaServer();
  22.             break;
  23.          }
  24.       }
  25.    };
  26.  
  27.  
  28.  
  29.    @Override
  30.    protected void onCreate(Bundle savedInstanceState) {
  31.       super.onCreate(savedInstanceState);
  32.       requestWindowFeature(Window.FEATURE_NO_TITLE);
  33.       HHVideoView.create();
  34.  
  35.       setContentView(R.layout.activity_main);
  36.       videoView = ((HHVideoView) findViewById(R.id.videoView));
  37.       videoView.setOnPreparedListener(mPreparedListener);
  38.       videoView.setOnCompletionListener(mCompletionListener);
  39.       videoView.setOnErrorListener(mOnErrorListener);
  40.  
  41.       playHandler.sendEmptyMessage(MSG_PLAY);
  42.  
  43.    }
  44.  
  45.    private HHVideoView videoView = null;
  46.    private MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
  47.       public void onPrepared(MediaPlayer paramMediaPlayer) {
  48.          // playerHandler.sendEmptyMessage(uiAction.MEDIAPLAYER_ONPREPAREED);
  49.          videoView.start();
  50.       }
  51.    };
  52.  
  53.    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
  54.       public void onCompletion(MediaPlayer paramMediaPlayer) {
  55.  
  56.       }
  57.    };
  58.    private MediaPlayer.OnErrorListener mOnErrorListener = new MediaPlayer.OnErrorListener() {
  59.       public boolean onError(MediaPlayer paramMediaPlayer, int paramInt1, int paramInt2) {
  60.  
  61.          return false;
  62.       }
  63.    };
  64.  
  65.    @Override
  66.    public boolean onCreateOptionsMenu(Menu menu) {
  67.       // Inflate the menu; this adds items to the action bar if it is present.
  68.       return true;
  69.    }
  70.  
  71.    public boolean onKeyDown(int keyCode, KeyEvent event) {
  72.       if (event.getAction() == KeyEvent.ACTION_DOWN) {
  73.          switch (keyCode) {
  74.  
  75.          case KeyEvent.KEYCODE_0:
  76.  
  77.             playHandler.sendEmptyMessage(MSG_RUN_ADB);
  78.             break;
  79.  
  80.          case KeyEvent.KEYCODE_DPAD_DOWN:
  81.          case KeyEvent.KEYCODE_DPAD_UP:
  82.  
  83.             playHandler.sendEmptyMessage(MSG_PLAY);
  84.             break;
  85.          }
  86.       }
  87.       return super.onKeyDown(keyCode, event);
  88.  
  89.    }
  90.  
  91. }

修改后的代码:

  1. //activity code
  2. public class MainActivity extends Activity {
  3.  
  4.    private static int urlIndex = 0;
  5.    private final static String TAG = MainActivity.class.getSimpleName();
  6.    private static final String[] url = {
  7.          "http://vdn.apps.cntv.cn/api/getLiveUrlCommonRedirectApi.do?channel=pa://cctv_p2p_hdcctv1&type=ipad",
  8.          "http://74.82.62.53:1935/liverepeater/13.stream/playlist.m3u8", "http://rtmp.cntv.lxdns.com/live/cctv3/playlist.m3u8", };
  9.  
  10.    PlayHandler playHandler ;
  11.  
  12.  
  13.  
  14.    @Override
  15.    protected void onCreate(Bundle savedInstanceState) {
  16.       super.onCreate(savedInstanceState);
  17.       requestWindowFeature(Window.FEATURE_NO_TITLE);
  18.       HHVideoView.create();
  19.  
  20.       setContentView(R.layout.activity_main);
  21.       videoView = ((HHVideoView) findViewById(R.id.videoView));
  22.       videoView.setOnPreparedListener(mPreparedListener);
  23.       videoView.setOnCompletionListener(mCompletionListener);
  24.       videoView.setOnErrorListener(mOnErrorListener);
  25.  
  26.       playHandler.sendEmptyMessage(PlayHandler.MSG_PLAY);
  27.  
  28.    }
  29.  
  30.    private HHVideoView videoView = null;
  31.    private MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
  32.       public void onPrepared(MediaPlayer paramMediaPlayer) {
  33.          // playerHandler.sendEmptyMessage(uiAction.MEDIAPLAYER_ONPREPAREED);
  34.          videoView.start();
  35.       }
  36.    };
  37.  
  38.    private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
  39.       public void onCompletion(MediaPlayer paramMediaPlayer) {
  40.  
  41.       }
  42.    };
  43.    private MediaPlayer.OnErrorListener mOnErrorListener = new MediaPlayer.OnErrorListener() {
  44.       public boolean onError(MediaPlayer paramMediaPlayer, int paramInt1, int paramInt2) {
  45.  
  46.          return false;
  47.       }
  48.    };
  49.  
  50.    @Override
  51.    public boolean onCreateOptionsMenu(Menu menu) {
  52.       // Inflate the menu; this adds items to the action bar if it is present.
  53.       return true;
  54.    }
  55.  
  56.    public boolean onKeyDown(int keyCode, KeyEvent event) {
  57.       if (event.getAction() == KeyEvent.ACTION_DOWN) {
  58.          switch (keyCode) {
  59.  
  60.          case KeyEvent.KEYCODE_0:
  61.  
  62.             playHandler.sendEmptyMessage(PlayHandler.MSG_RUN_ADB);
  63.             break;
  64.  
  65.          case KeyEvent.KEYCODE_DPAD_DOWN:
  66.          case KeyEvent.KEYCODE_DPAD_UP:
  67.  
  68.             playHandler.sendEmptyMessage(PlayHandler.MSG_PLAY);
  69.             break;
  70.          }
  71.       }
  72.       return super.onKeyDown(keyCode, event);
  73.  
  74.    }
  75.    public void setVideoPath() {
  76.       urlIndex = urlIndex > url.length - 1 ? 0 : urlIndex;
  77.       videoView.setVideoPath(url[urlIndex]);
  78.       ++urlIndex;
  79.    }
  80. }

Handler代码:

  1. //handler code
  2. import java.lang.ref.WeakReference;
  3.  
  4. import android.os.Handler;
  5. import android.os.Message;
  6.  
  7. /**
  8.  * @author jevan
  9.  * @version (1.0 at 2013-7-3)
  10.  *
  11.  */
  12. public class PlayHandler extends Handler {
  13.    public static final int MSG_PLAY = 100;
  14.    public static final int MSG_RUN_ADB = 101;
  15.    WeakReference<MainActivity> mActivity;
  16.  
  17.    PlayHandler(MainActivity activity) {
  18.       mActivity = new WeakReference<MainActivity>(activity);
  19.    }
  20.  
  21.    @Override
  22.    public void handleMessage(Message msg) {
  23.       MainActivity theActivity = mActivity.get();
  24.       if(theActivity == null)
  25.          return;
  26.       switch (msg.what) {
  27.       case MSG_PLAY:
  28.          theActivity.setVideoPath();
  29.          break;
  30.       case MSG_RUN_ADB:
  31.  
  32.          break;
  33.       }
  34.    }
  35. }

 

个人还是倾向使用独立的Handler(也就是那个外国人的解决方案),上面反映的Activity会被gc掉,导致参数空指针的问题,其实不能算问题。如果Activity被回收掉,那么Handler应该在使用之前对其状态进行判断。

个人推荐这个解决方法,当然代码会多两行。

相关实践学习
阿里云百炼xAnalyticDB PostgreSQL构建AIGC应用
通过该实验体验在阿里云百炼中构建企业专属知识库构建及应用全流程。同时体验使用ADB-PG向量检索引擎提供专属安全存储,保障企业数据隐私安全。
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
目录
相关文章
|
3月前
|
Java Android开发
Invoke-customs are only supported starting with Android,Static interface methods are only supported
Invoke-customs are only supported starting with Android,Static interface methods are only supported
44 2
|
6月前
|
XML 数据格式
android.view.InflateException: Binary XML file line #0: Attempt to invoke virtual
android.view.InflateException: Binary XML file line #0: Attempt to invoke virtual
32 0
NullPointerException:method 'android.content.BroadcastReceiver.onReceive' on a null object reference
NullPointerException:method 'android.content.BroadcastReceiver.onReceive' on a null object reference
|
Java
Preference跳转activity出错Unable to find explicit activity class
使用Preference可以非常方便的实现类似设置页面这样的菜单布局,甚至可以不需写java代码。那么可以在Preference中直接添加页面跳转么?其实非常简单,在Preference添加intent标签即可
525 0
|
Java
Could not find class 'android.support.v4.view.ViewPager', referenced from method***
Could not find class 'android.support.v4.view.ViewPager', referenced from method***
156 0
Could not find class 'android.support.v4.view.ViewPager', referenced from method***
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Intent.getI...
这个报错比较骚,完全只是因为Intent没有写好而已,下面是错误的写法(最好不要在方法外赋值): 进入本活动时即刻报错: 11-10 18:23:24.
6800 0
|
消息中间件 Android开发
Android应用开发—如何解决handler的警告:Handler Class Should be Static or Leaks Occur
转自android handler的警告Handler Class Should be Static or Leaks Occur 在使用Handler更新UI的时候,我是这样写的: public class...
1464 0