}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private Handler mHandler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == 1) {
//something
}
}
};
}
也许有人会说,mHandler 并未作为静态变量持有 Activity 引用,生命周期可能不会比 Activity 长,应该不一定会导致内存泄漏呢,显然不是这样的! 熟悉 `Handler` 消息机制的都知道,`mHandler` 会作为成员变量保存在发送的消息 `msg` 中,即 `msg` 持有 `mHandler` 的引用,而 `mHandle`r 是 `Activity` 的非静态内部类实例,即 `mHandler` 持有 `Activity` 的引用,那么我们就可以理解为 `msg` 间接持有 `Activity` 的引用。`msg` 被发送后先放到消息队列 `MessageQueue` 中,然后等待 `Looper` 的轮询处理( `MessageQueue` 和 `Looper` 都是与线程相关联的,`MessageQueue` 是 `Looper` 引用的成员变量,而 `Looper` 是保存在 `ThreadLocal` 中的)。那么当 `Activity` 退出后,`msg` 可能仍然存在于消息队列 `MessageQueue` 中未处理或者正在处理,那么这样就会导致 `Activity` 无法被回收,以至发生 `Activity` 的内存泄漏。 通常在 Android 开发中如果使用内部类,但又要避免内存泄漏,一般都会采用**静态内部类 + 弱引用**的方式:
public class MainActivity extends AppCompatActivity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new MyHandler(this);
start();
}
private void start() {
Message msg = Message.obtain();
msg.what = 1;
mHandler.sendMessage(msg);
}
private static class MyHandler extends Handler {
private WeakReference<MainActivity> activityWeakReference;
public MyHandler(MainActivity activity) {
activityWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(@NonNull Message msg) {
MainActivity activity = activityWeakReference.get();
if (activity != null) {
if (msg.what == 1) {
//something
}
}
}
}
}
mHandler 通过弱引用的方式持有 Activity,当 GC 执行垃圾回收时,遇到 Activity 就会被回收并释放所有占据的内存单元。这样就不会发生内存泄漏了。 上面的做法确实避免了 Activity 导致的内存泄漏,发送的 msg 不再已经没有持有 Activity 的引用了,但是 msg 还是有可能存在消息队列 MessageQueue 中,所有更好的是在 Activity 销毁时就将 mHandler 的回调和发送的消息给移除掉。
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
### []( )Thread、AsyncTask
非静态内部类造成内存泄漏还有一种情况就是使用 Thread 或者 AsyncTask。 比如在 Activity 中直接 new 一个子线程 Thread:
public class ThreadActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread);
new Thread(new Runnable() {
@Override
public void run() {
//Something
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
或者直接新建 AsyncTask 异步任务:
public class AsyncTaskActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
//something
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
}
很多初学者都会像上面这样新建线程和异步任务,殊不知这样的写法非常不友好,这样方式新建的子线程 Thread 和 AsyncTask 都是匿名内部类对象,默认就隐式的持有外部 Activity 的引用,导致 Activity 内存泄漏。要避免内存泄漏的话还是需要像上面 Handler 一样使用**静态内部类 + 弱引用**的方式。
[]( )未取消注册或回调导致内存泄漏
----------------------------------------------------------------------------
比如我们在 Activity 中注册广播,如果在 Activity 销毁后不取消注册,那么这个广播会一直存在系统中,同上面所说的非静态内部类一样持有 Activity 引用,导致内存泄漏。因此注册广播后在 Activity 销毁后一定要取消注册。
public class BroadcastActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
registerReceiver(mReceiver, new IntentFilter());
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//接收到广播需要做的逻辑
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
}
在注册观察者模式的时候,如果不及时取消也会造成内存泄漏。比如使用 Retrofit + RxJava 注册网络请求的观察者回调,同样作为匿名内部类持有外部引用,所以需要记得在不用或者销毁的时候取消注册。
[]( )Timer 和 TimerTask 导致内存泄漏
--------------------------------------------------------------------------------------
Timer 和 TimerTask 在 Android 中通常会被用来做一些计时或循环任务,比如实现无限轮播的 ViewPager:
public class TimerActivity extends AppCompatActivity {
private ViewPager mViewPager;
private PagerAdapter mAdapter;
private Timer mTimer;
private TimerTask mTimerTask;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
init();
mTimer.schedule(mTimerTask, 3000, 3000);
}
private void init() {
mViewPager = findViewById(R.id.view_pager);
mAdapter = new ViewPagerAdapter();
mViewPager.setAdapter(mAdapter);
mTimer = new Timer();
mTimerTask = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
loopViewpager();
}
});
}
};
}
private void loopViewpager() {
if (mAdapter.getCount() > 0) {
int curPos = mViewPager.getCurrentItem();
curPos = (++curPos) % mAdapter.getCount();
mViewPager.setCurrentItem(curPos);
}
}
private void stopLoopViewPager() {
if (mTimer != null) {
mTimer.cancel();
mTimer.purge();
mTimer = null;
}
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
stopLoopViewPager();
}
}
当我们 Activity 销毁时,有可能 Timer 还在继续等待执行 TimerTask,它持有 Activity 的引用不能被回收,因此当我们 Activity 销毁的时候要立即 cancel 掉 Timer 和 TimerTask,以避免发生内存泄漏。
## 总结
最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,**从来都是我们去适应环境,而不是环境来适应我们!**
> 这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。

**[CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》](https://codechina.csdn.net/m0_60958482/android_p7)**
> 网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,**从来都是我们去适应环境,而不是环境来适应我们!**
> 这里附上我整理的几十套腾讯、字节跳动,京东,小米,头条、阿里、美团等公司19年的Android面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。
[外链图片转存中...(img-cISdeZYQ-1631090798006)]
**[CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》](https://codechina.csdn.net/m0_60958482/android_p7)**
> 网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
技术进阶之路很漫长,一起共勉吧~
版权声明:本文为m0_61408464原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。