有关beanhandler的作用内存泄漏是怎么一回事

下次自动登录
关注移动互联网和移动APP开发工具、开发框架、测试工具、微信开发、Android源码、Android开源类库以及各种开源组件的IT科技网站
现在的位置:
Android开发:详解Handler的内存泄露
内存泄露在Android开发中非常常见
内存泄露的定义:本该被回收的对象不能被回收而停留在堆内存中
内存泄露出现的原因:当一个对象已经不再被使用时,本该被回收但却因为有另外一个正在使用的对象持有它的引用从而导致它不能被回收。 这就导致了内存泄漏。
本文将详细讲解内存泄露的其中一种情况:在Handler中发生的内存泄露
我们先来看下日常Handler的一般用法:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
//主线程创建时便自动创建Looper和对应的MessageQueue,之前执行Loop()进入消息循环
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化Handler
//这里并无指定Looper,即自动绑定当前线程(主线程)的Looper和MessageQueue
private Handler showhandler = new Handler(){
//通过复写handlerMessage()从而决定如何进行更新UI操作
public void handleMessage(Message msg) {
//UI更新操作
//启动子线程
new Thread(){
public void run() {
super.run();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
showhandler.sendEmptyMessageDelayed(0x1,10000);
}.start();
在上面的例子中,你会发现出现了严重的警告:
Paste_Image.png
从上图可以看出来,这个警告的原因是:该Handler造成了严重的 内存泄漏
那么,该Handler是怎么样造成内存泄露的呢?
2. 内存泄露原因
2.1 造成内存泄露的源头
根据图片可以分析,内存泄露显示出现在:
即Handler四件套:Looper+MessageQueue+Message+Handler
最终的泄露发生在Handler类的外部类 - MainActivity类
2.2 如何造成内存泄露
首先,我们需要了解到:
主线程的Looper对象会伴随该应用程序的整个生命周期
在Java里, 非静态内部类 和 匿名类 都会潜在引用它们所属的外部类
在了解到上述两条后,从上面的代码中可以知道:
在发送的延迟空消息(EmptyMessageDelayed)后、消息处理被前,该消息会一直保存在主线程的消息队列里持续10s
在这延时10s内,该消息内部持有对handler的引用,由于handler属于非静态内部类,所以又持有对其外部类(即MainActivity实例)的潜在引用,引用关系如下图
这条引用关系会一直保持直到消息得到处理,从而,这阻止了MainActivity被垃圾回收器(GC)回收,同时造成应用程序的内存泄漏,如下图:
3. 解决方案
3.1 解决方案1:使用静态内部类+弱引用
上面提到,在Java里, 非静态内部类 和 匿名类 都会潜在的引用它们所属的外部类。
但是, 静态内部类不会。
所以,避免内存泄露的解决方案是:只需要将Handler的子类设置成静态内部类
同时,还可以加上 使用WeakReference弱引用持有Activity实例
原因:弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
解决代码如下:
public class MainActivity extends AppCompatActivity {
//将Handler改成静态内部类
private static class FHandler extends Handler{
//定义弱引用实例
private WeakReference&Activity&
//在构造方法中传入需要持有的Activity实例
public MyHandler(Activity activity) {
reference = new WeakReference&Activity&(activity); }
//通过复写handlerMessage()从而决定如何进行更新UI操作
public void handleMessage(Message msg) {
//省略代码
protected void onCreate(Bundle savedInstanceState) {
//主线程创建时便自动创建Looper和对应的MessageQueue,之前执行Loop()进入消息循环
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//实例化Handler的子类
//这里并无指定Looper,即自动绑定当前线程(主线程)的Looper和MessageQueue
private final Handler showhandler = new FHandler();
//启动子线程
new Thread(){
public void run() {
super.run();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
showhandler.sendEmptyMessageDelayed(0x1,10000);
}.start();
3.2 解决方案2:当外部类结束生命周期时清空消息队列
从上面分析,内存泄露的原因是: 当Activity结束生命周期时,Handler里的Message可能还没处理完,从而导致一系列的引用关系。
其实,我们只要在当Activity结束生命周期时清除掉消息队列(MessageQueue)里的所有Message,那么这一系列引用关系就不会存在,就能防止内存泄露。
解决方案:当Activity结束生命周期时(调用onDestroy()方法),同时清除消息队列里的所有回调消息(调用removeCallbacksAndMessages(null))
代码如下:
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
经过上述两个解决方案,在Handler里的内存泄露问题就不会再出现了!
本文总结的是关于Handler的一些小事:内存泄露,阅读完本文后相信你已经懂得Handler内存泄露的原理和详细的解决方案
接下来,我会继续讲解Android开发中关于Handler和多线程的知识,包括Handler源码、继承Thread类、实现Runnable接口、Handler等等。
来自:/p/ed9e15eff47a
【上篇】【下篇】4798人阅读
Android(9)
Android中有关Handler的使用(一)
&&&&&& 一个Handler允许你发送和处理消息(Message)以及与一个线程的消息队列相关的Runnable对象。每个Handler实例都和单个线程以及该线程的消息队列有关。当你创建了一个新Handler,它就会和创建它的线程/消息队列绑定,在那以后,它就会传递消息以及runnable对象给消息队列,然后执行它们。
&&&&&& 需要使用Handler有两大主要的原因:
&&&&&& (1)在将来的某个时间点调度处理消息和runnable对象;
&&&&&& (2)将需要执行的操作放到其他线程之中,而不是自己的;
&&&&& 调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和sendMessageDelayed(Message, long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)
&&&&& 【以上这段翻译自android sdk】
&&&&& Handler在实际开发中是很常用的,主要是用来接收子线程发送的数据,然后主线程结合此数据来更新界面UI。
&&&&& Android应用程序启动时,他会开启一个主线程(也就是UI线程),管理界面中的UI控件,进行事件派发,比如说:点击一个按钮,Android会分发事件到Button上从而来响应你的操作。但是当你需要执行一个比较耗时的操作的话,例如:进行IO操作,网络通信等等,若是执行时间超过5s,那么Android会弹出一个&经典&的ANR无响应对话框,然后提示按&Force quit&或是&Wait&。解决此类问题的方法就是:我们把一些耗时的操作放到子线程中去执行。但因为子线程涉及到UI更新,而Android主线程是线程不安全的,所以更新UI的操作只能放在主线程中执行,若是放在子线程中执行的话很会出问题。所以这时就需要一种机制:主线程可以发送&命令/任务&给子线程执行,然后子线程反馈执行结果;
!你必需要知道的:
&&&&& 若在主线程中实例化一个Handler对象,例如:
&&&&& Handler mHandler = new Handler();
&&&&& 此时它并没有新派生一个线程来执行此Handler,而是将此Handler附加在主线程上,故此时若你在Handler中执行耗时操作的话,还是会弹出ANR对话框!
下面就Handler的使用举一些例子,加深理解。
&&&&& 1、post版本的Handler使用示例:
package com.dxyh.
import android.app.A
import android.content.C
import android.os.B
import android.os.H
import android.util.L
import android.view.V
import android.view.View.OnClickL
import android.widget.B
public class MainActivity extends Activity
implements OnClickListener {
private final static String TAG = "HandlerTest";
private final static int DELAY_TIME = 1000;
private Button btnS
private Button btnS
Context mContext =
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext =
Log.i(TAG, "Main thread id = " +
Thread.currentThread().getId());
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnClickListener(this);
btnStop = (Button) findViewById(R.id.btn_stop);
btnStop.setOnClickListener(this);
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_start:
mHandler.postDelayed(workRunnable, DELAY_TIME);
case R.id.btn_stop:
mHandler.removeCallbacks(workRunnable);
Runnable workRunnable = new Runnable() {
int counter = 0;
public void run() {
if (counter++ & 1) {
Log.i(TAG, "workRunnable thread id = " +
Thread.currentThread().getId());
mHandler.postDelayed(workRunnable, DELAY_TIME);
Handler mHandler = new Handler();
&&&&& Logcat显示如下:
说明:发现thread id是相同的,这就说明:默认情况下创建的Handler会绑定到主线程上,你不能做太耗时的操作。
&&&&& 本文暂止,下文我们会介绍sendMessage版本的Handler的使用。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:158215次
积分:1323
积分:1323
排名:千里之外
原创:12篇
评论:24条
(3)(1)(3)(7)android(12)
内存泄漏常见原因总结
1.非静态内部类的静态实例
public class MainActivityextends Activity
static Demo sInstance = null;
public void onCreate(BundlesavedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (sInstance == null)
sInstance= new Demo();
class Demo
voiddoSomething()
System.out.print("dosth.");
2.Activity的静态成员变量
Drawable的对象的内部Callback持有activity的引用,当Activity finish()之后,静态成员drawable始终持有这个Activity的引用,导致内存释放不了。
Context,Activity内部如果有一个Context的成员变量,将导致Context引用指向的Activity对象释放不了。
public class MainActivity extends Activity {
private static Context mC
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mContext=MainActivity.this;
3.Handler造成的内存泄漏
3.1 Handler内存泄漏的原因
public class MainActivity extends Activity {
private Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
大家平时开发中喜欢在Activity中直接new一个Handler的匿名内部类,这样造成匿名内部类持有一个外部类(通常是Activity)的引用(不然怎么更新ui),但是Handler常常伴随着一个执行耗时操作的异步线程(如下载多张图片),如果在完成耗时操作之前,Activity退出,异步线程持有handler的引用,handler持有Activity的引用,从而导致内存泄漏。
3.2 防止Handler内存泄漏的措施
通过程序逻辑来进行保护
在关闭Activity的时候,把线程也关了;
如果Handler是被delay的Message持有的引用,在Activity的onDestroy()方法中,调用Handler响应书的removeCallbacks()方法,把消息对象从消息队列移除就行了。
将Handler声明为静态类
静态类不持有外部类的引用,所以Activity可以被随意回收,代码如下:
private static class MyHandler extends Handler {
public void handleMessage(Message msg) {
使用弱引用
当Activity在内存中的对象没有任何引用,使用弱引用会让Activity对象很容易被Gc回首。代码如下:
private static class MyHandler extends Handler {
WeakReference&CrmContactActivity& mR
public MyHandler(CrmContactActivity activity) {
mReference = new WeakReference&CrmContactActivity&(activity);
public void handleMessage(Message msg) {
final CrmContactActivity activity = mReference.get();
if (activity == null || activity.isFinishing()) {
if (msg.what == LOAD_MORE) {
activity.panyName);
} else if (msg.what == THE_END) {
activity.showViewIfHasCompanyName((ArrayList&CustomerModel&) activity.matchedCustomerList);
4.注册某个对象后没有反注册
广播接收器注册后在Activity退出时忘了反注册,一些利用观察者模式的第三方开源库在使用时,忘了反注册(如EventBus)。
正确代码如下:
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
5.集合对象没清理造成的内存泄漏
把大量对象的引用放入集合中,但我们不需要该对象时,记得从集合中将不需要的引用清理掉,同理,当对象不需要时,记得将对象的引用设置为null。
6.资源文件未关闭
最常见的是文件流执行完读写操作后,忘记关闭了输入流,输出流;数据库、Content Provider操作完后Cursor忘记了close等等。
安全一点的方式是在写代码的时候,首先写完头尾,避免尾部关闭操作忘记了谢。
7.代码不严谨
Bitmap对象使用完后,忘记了调用recycle()方法销毁;
解析图片的时候忘记了设置采样率
自定义View时TypedArray使用完后忘记调用recycle()方法释放内存
ListView的适配器类中没有复用convertView
未采用软引用等
8.关于内存泄漏的调试
我有一篇博客介绍我开发过程中一次典型的内存泄漏案例,这个案例中介绍了内存泄漏检测工具MAT的使用,博客链接如下:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4940次
排名:千里之外
原创:13篇
(1)(3)(2)(3)(4)(3)(1)安卓面试题 5 – 关于内存泄漏 - 推酷
安卓面试题 5 – 关于内存泄漏
什么是内存泄漏
内存泄露,简单的说,就是该被释放的内存没有被释放,一直被某个或某些实例所引用但不能被使用,导致GC不能回收,造成内存泄漏。总结的说,可以理解为长生命周期的对象一直持有短生命周期对象的引用,导致短生命周期对象一直被引用而无法被GC回收,内存泄漏是造成OOM的主要原因之一,当一个应用中产生的内存泄漏比较多时,就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash。。
安卓中常见的内存泄漏场景
1.单例造成内存泄漏
因为单例模式有其静态的特点,其生命周期和应用一样长,如果单例对象中包含了一个其他对象的引用,那么即使这个对象不再使用,依然存在一个单例对象引用它,造成无法回收。比如:
AppManager&{
AppManager&
AppManager(Context&context)&{
.context&=&
AppManager&getInstance(Context&context)&{
(instance&!=&
instance&=&
AppManager(context);
这个单例对象包含了一个Context的引用,所以此时要考虑,
&如果传入一个Application Context,它的生命周期和应用一样长,没问题。
如果传入一个Activity Context,Activity退出销毁但任然被单例所引用了,会导致内存泄漏。
所以正确的单例应该修改为下面这种方式:
AppManager&{
AppManager&
AppManager(Context&context)&{
.context&=&context.getApplicationContext();
AppManager&getInstance(Context&context)&{
(instance&!=&
instance&=&
AppManager(context);
2.非静态内部类创建其静态实例造成内存泄漏
有的时候我们可能会在启动频繁的Activity中,为了避免重复创建相同的数据资源,会出现这种写法:
MainActivity&
AppCompatActivity&{
TestResource&mResource&=&
onCreate(Bundle&savedInstanceState)&{
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
(mManager&==&
mManager&=&
TestResource();
TestResource&{
这样就在Activity内部创建了一个非静态内部类的单例,每次启动Activity时都会使用该单例的数据,这样虽然避免了资源的重复创建,不过这种写法却会造成内存泄漏,因为 非静态内部类默认会持有外部类的引用 ,而又使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。正确的做法为:
将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用Application Context 。
3.匿名内部类/异步线程造成内存泄漏
如下这两个示例可能每个人都这样写过:
//——————test1
AsyncTask&Void,&Void,&Void&()&{
Void&doInBackground(Void...&params)&{
SystemClock.sleep(
}.execute();
//——————test2
Runnable()&{
SystemClock.sleep(
}).start();
上面的异步任务和Runnable都是一个 匿名内部类 , 因此它们对当前Activity都有一个隐式引用 。如果Activity在销毁之前,任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。正确的做法还是使用静态内部类的方式,如下:
MyAsyncTask&
AsyncTask&Void,&Void,&Void&&{
WeakReference&Context&&weakR
MyAsyncTask(Context&context)&{
weakReference&=&
WeakReference&&(context);
Void&doInBackground(Void...&params)&{
SystemClock.sleep(
onPostExecute(Void&aVoid)&{
.onPostExecute(aVoid);
MainActivity&activity&=&(MainActivity)&weakReference.get();
(activity&!=&
MyRunnable&
implements
SystemClock.sleep(
//——————
MyRunnable()).start();
MyAsyncTask(
).execute();
这样就避免了Activity的内存资源泄漏,当然在Activity销毁时候也应该取消相应的任务AsyncTask::cancel(),避免任务在后台执行浪费资源。
4.Handler机制造成内存泄漏
这个在上一篇也有说到,再次总结下。一般我们写Handler:
MainActivity&
AppCompatActivity&{
Handler&mHandler&=&
Handler()&{
handleMessage(Message&msg)&{
onCreate(Bundle&savedInstanceState)&{
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
loadData(){
//...request
Message&message&=&Message.obtain();
mHandler.sendMessage(message);
其中mHandler作为一个非静态匿名内部类,持有一个外部类—MainActivity的引用,我们知道对于消息机制是Looper不断的轮询从消息队列取出未处理的消息交给handler处理,而对于这个例子,每一个消息又持有一个mHandler的引用,每一个mHandler又持有MainActivity的引用,所以如果在Activity退出后,消息队列中还存在未处理完的消息,导致该Activity一直被引用,其内存资源无法被回收,导致了内存泄漏。一般我们使用静态内部类和弱引用的写法写Handler。
MainActivity&
AppCompatActivity&{
MyHandler&mHandler&=&
MyHandler(
TextView&mTextView&;
MyHandler&
WeakReference&Context&&
MyHandler(Context&context)&{
reference&=&
WeakReference&&(context);
handleMessage(Message&msg)&{
MainActivity&activity&=&(MainActivity)&reference.get();
(activity&!=&
activity.mTextView.setText(
onCreate(Bundle&savedInstanceState)&{
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView&=&(TextView)findViewById(R.id.textview);
loadData();
loadData()&{
//...request
Message&message&=&Message.obtain();
mHandler.sendMessage(message);
将Activity的引用声明为弱引用,可以被GC回收。(引用不一定为Context,也可以是Context的子类)
Java对引用的分类有 Strong reference, SoftReference, WeakReference, PhatomReference 四种。
在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大而且声明周期较长的对象时候,可以尽量应用软引用和弱引用技术。
5.资源未回收导致内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏(这个可以根据IDE的警告改进一部分)。
AS中查看内存泄漏
对 Activity 等组件的引用应该控制在 Activity 的生命周期之内; 如果不能就考虑使用 getApplicationContext 或者 getApplication,以避免 Activity 被外部长生命周期的对象引用而泄露。
尽量不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context ),即使要使用,也要考虑适时把外部成员变量置空;也可以在内部类中使用弱引用来引用外部类的变量。
对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以这样做避免内存泄漏:
将内部类改为静态内部类
静态内部类中使用弱引用来引用外部类的成员变量
Handler 的持有的引用对象最好使用弱引用,资源释放时也可以清空 Handler 里面的消息。比如在 Activity onStop 或者 onDestroy 的时候,取消掉该 Handler 对象的 Message和 Runnable.
在 Java 的实现过程中,也要考虑其对象释放,最好的方法是在不使用某对象时,显式地将此对象赋值为 null,比如使用完Bitmap 后先调用 recycle(),再赋为null,清空对图片等资源有直接引用或者间接引用的数组(使用 array.clear() ; array = null)等,最好遵循谁创建谁释放的原则。
正确关闭资源,对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销。
保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致Android中Handler引起的内存泄露问题解决办法
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Android中Handler引起的内存泄露问题解决办法,本文讲解了导致内存泄露的情景,并给出了修改后的代码,需要的朋友可以参考下
在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。通常我们的代码会这样实现。
public class SampleActivity extends Activity {
& private final Handler mLeakyHandler = new Handler() {
&&& @Override
&&& public void handleMessage(Message msg) {
&&&&& // ...
但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告
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
看到这里,可能还是有一些搞不清楚,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下。
1.当一个Android应用启动的时候,会自动创建一个供应用主线程使用的Looper实例。Looper的主要工作就是一个一个处理消息队列中的消息对象。在Android中,所有Android框架的事件(比如Activity的生命周期方法调用和按钮点击等)都是放入到消息中,然后加入到Looper要处理的消息队列中,由Looper负责一条一条地进行处理。主线程中的Looper生命周期和当前应用一样长。
2.当一个Handler在主线程进行了初始化之后,我们发送一个target为这个Handler的消息到Looper处理的消息队列时,实际上已经发送的消息已经包含了一个Handler实例的引用,只有这样Looper在处理到这条消息时才可以调用Handler#handleMessage(Message)完成消息的正确处理。
3.在Java中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用。静态的内部类不会持有外部类的引用。关于这一内容可以查看细话
确实上面的代码示例有点难以察觉内存泄露,那么下面的例子就非常明显了
public class SampleActivity extends Activity {
& private final Handler mLeakyHandler = new Handler() {
&&& @Override
&&& public void handleMessage(Message msg) {
&&&&& // ...
& @Override
& protected void onCreate(Bundle savedInstanceState) {
&&& super.onCreate(savedInstanceState);
&&& // Post a message and delay its execution for 10 minutes.
&&& mLeakyHandler.postDelayed(new Runnable() {
&&&&& @Override
&&&&& public void run() { /* ... */ }
&&& }, 1000 * 60 * 10);
&&& // Go back to the previous Activity.
&&& finish();
分析一下上面的代码,当我们执行了Activity的finish方法,被延迟的消息会在被处理之前存在于主线程消息队列中10分钟,而这个消息中又包含了Handler的引用,而Handler是一个匿名内部类的实例,其持有外面的SampleActivity的引用,所以这导致了SampleActivity无法回收,进行导致SampleActivity持有的很多资源都无法回收,这就是我们常说的内存泄露。
注意上面的new Runnable这里也是匿名内部类实现的,同样也会持有SampleActivity的引用,也会阻止SampleActivity被回收。
要解决这种问题,思路就是不适用非静态内部类,继承Handler时,要么是放在单独的类文件中,要么就是使用静态内部类。因为静态的内部类不会持有外部类的引用,所以不会导致外部类实例的内存泄露。当你需要在静态内部类中调用外部的Activity时,我们可以使用弱引用来处理。另外关于同样也需要将Runnable设置为静态的成员属性。注意:一个静态的匿名内部类实例不会持有外部类的引用。 修改后不会导致内存泄露的代码如下:
public class SampleActivity extends Activity {
&& * Instances of static inner classes do not hold an implicit
&& * reference to their outer class.
& private static class MyHandler extends Handler {
&&& private final WeakReference&SampleActivity& mA
&&& public MyHandler(SampleActivity activity) {
&&&&& mActivity = new WeakReference&SampleActivity&(activity);
&&& @Override
&&& public void handleMessage(Message msg) {
&&&&& SampleActivity activity = mActivity.get();
&&&&& if (activity != null) {
&&&&&&& // ...
& private final MyHandler mHandler = new MyHandler(this);
&& * Instances of anonymous classes do not hold an implicit
&& * reference to their outer class when they are "static".
& private static final Runnable sRunnable = new Runnable() {
&&&&& @Override
&&&&& public void run() { /* ... */ }
& @Override
& protected void onCreate(Bundle savedInstanceState) {
&&& super.onCreate(savedInstanceState);
&&& // Post a message and delay its execution for 10 minutes.
&&& mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
&&& // Go back to the previous Activity.
&&& finish();
其实在Android中很多的内存泄露都是由于在Activity中使用了非静态内部类导致的,就像本文提到的一样,所以当我们使用时要非静态内部类时要格外注意,如果其实例的持有对象的生命周期大于其外部类对象,那么就有可能导致内存泄露。个人倾向于使用文章的静态类和弱引用的方法解决这种问题。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 handler 内存泄漏 的文章

 

随机推荐