Handler的内存泄露几解决办法以及闪屏效果的实现
2015-12-08 21:31
288 查看
Handle实现机制涉及的对象:
Message :表示要传递一个消息,(消息对象,内部使用链表数据结构实现一个消息池,用于重复利用, 避免大量创建消息对象,造成对象浪费)
MessageQueue :存放消息对象的消息队列(先进先出)
Looper:looper对象负责管理当前线程的消息队列,用于循环检查消息队列,从消息队列中一个一个的取出消息(Loop 如同一个工人,管MessageQueue )
Handler:Handler对象负责把消息push到消息队列,以及接收Looper从消息队列中读取到的数据
Android启动程序的时候,会在UI线程中创建一个MessageQueue。
Handler的内存泄露问题:
在使用初次handler的时候,代码会写成如下方式:
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持有的很多资源都无法回收,这就是我们常说的内存泄露
内存泄露: OS会给所有的进程分配的空间,正在被某一个进程榨干,结果是进程运行的时间越长,占用的存储空间越多,最终占用完全部的存储空间,导致系统崩溃。
出现原因: Handler引用阻止了GC对Activity的回收
1:在java中,非静态(匿名)内部类会默认隐性引用外部类对象,而静态内部类不会引用外部类对象,
2:如果外部类时Activity则会引起Activity内存泄露。
3:当外部类是Activity,在外部类中定义一个Handler 时,Handler对象会持有外部类的引用,在使用时如果要退出Activity时,如果此时Handler还在工作,此时Handler引用持有外部类的引用,此时Activity是无法被回收的,此时就会出现内存泄露。
解决办法:
采用静态内部类与弱引用结合的方式
继承handler的时候,要么放在单独的类文件中,要么放在单独的类文件中,要么就是使用静态内部类,因为静态内部类不会持有外部类的引用,所有不会导致外部类的实例的内存泄露,当在静态静态的内部类中调用外部Activity时,可以使用弱引用来处理,
如下修改后就不会出现内存泄露:
public class HandlerMemoryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memory);
// 使用Handler延时执行一个Runnable(10分钟)
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("Runnable");
}
},1000*60*10);
finish();// 关闭当前Activity
}
private MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler{
//创建一个弱引用
WeakReference<HandlerMemoryActivity> weakReference;
public MyHandler (HandlerMemoryActivity activity){
weakReference = new WeakReference<HandlerMemoryActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerMemoryActivity handlerMemoryActivity = weakReference.get();
if (handlerMemoryActivity!=null){
// 执行相关的UI操作
}
}
}
}
使用Handler实现闪屏:
当首次注册一个APP时,会有一些提示的信息,提醒用户进行注册或登陆是界面显得很友好。
代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.postDelayed(new Runnable() {
@Override
public void run() {
startAnotherActivity();
}
},3000);
}
private void startAnotherActivity() {
Intent intent = new Intent(this,Main2Activity.class);
startActivity(intent);
}
private Handler handler = new Handler();
}
在布局文件中使用ImageView,
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/e"
/>
将程序运行至模拟器,显示一个图片,经过3秒(主程序设定)后,会返回到下一个业务界面。
Message :表示要传递一个消息,(消息对象,内部使用链表数据结构实现一个消息池,用于重复利用, 避免大量创建消息对象,造成对象浪费)
MessageQueue :存放消息对象的消息队列(先进先出)
Looper:looper对象负责管理当前线程的消息队列,用于循环检查消息队列,从消息队列中一个一个的取出消息(Loop 如同一个工人,管MessageQueue )
Handler:Handler对象负责把消息push到消息队列,以及接收Looper从消息队列中读取到的数据
Android启动程序的时候,会在UI线程中创建一个MessageQueue。
Handler的内存泄露问题:
在使用初次handler的时候,代码会写成如下方式:
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持有的很多资源都无法回收,这就是我们常说的内存泄露
内存泄露: OS会给所有的进程分配的空间,正在被某一个进程榨干,结果是进程运行的时间越长,占用的存储空间越多,最终占用完全部的存储空间,导致系统崩溃。
出现原因: Handler引用阻止了GC对Activity的回收
1:在java中,非静态(匿名)内部类会默认隐性引用外部类对象,而静态内部类不会引用外部类对象,
2:如果外部类时Activity则会引起Activity内存泄露。
3:当外部类是Activity,在外部类中定义一个Handler 时,Handler对象会持有外部类的引用,在使用时如果要退出Activity时,如果此时Handler还在工作,此时Handler引用持有外部类的引用,此时Activity是无法被回收的,此时就会出现内存泄露。
解决办法:
采用静态内部类与弱引用结合的方式
继承handler的时候,要么放在单独的类文件中,要么放在单独的类文件中,要么就是使用静态内部类,因为静态内部类不会持有外部类的引用,所有不会导致外部类的实例的内存泄露,当在静态静态的内部类中调用外部Activity时,可以使用弱引用来处理,
如下修改后就不会出现内存泄露:
public class HandlerMemoryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_memory);
// 使用Handler延时执行一个Runnable(10分钟)
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.out.println("Runnable");
}
},1000*60*10);
finish();// 关闭当前Activity
}
private MyHandler handler = new MyHandler(this);
private static class MyHandler extends Handler{
//创建一个弱引用
WeakReference<HandlerMemoryActivity> weakReference;
public MyHandler (HandlerMemoryActivity activity){
weakReference = new WeakReference<HandlerMemoryActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
HandlerMemoryActivity handlerMemoryActivity = weakReference.get();
if (handlerMemoryActivity!=null){
// 执行相关的UI操作
}
}
}
}
使用Handler实现闪屏:
当首次注册一个APP时,会有一些提示的信息,提醒用户进行注册或登陆是界面显得很友好。
代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.postDelayed(new Runnable() {
@Override
public void run() {
startAnotherActivity();
}
},3000);
}
private void startAnotherActivity() {
Intent intent = new Intent(this,Main2Activity.class);
startActivity(intent);
}
private Handler handler = new Handler();
}
在布局文件中使用ImageView,
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/e"
/>
将程序运行至模拟器,显示一个图片,经过3秒(主程序设定)后,会返回到下一个业务界面。
相关文章推荐
- html5结合JavaScript实现龙播图
- Cocos2d-x 3.2 大富翁游戏项目开发-第七部分 获取角色路径_1
- lucene-SpanQuery跨度查询基础
- POJ3273 二分与最大值最小化
- 485线路保护
- 杭电oj 1014
- Dropout中隐层节点的忽略比例与DAE中加噪比例参数的区别
- POJ 1830 (高斯消元)
- STM32库函数(3):库文件stm32f10x_flash.c内的函数
- BZOJ1295: [SCOI2009]最长距离
- Lucene中的 Query对象
- Exchange Server 2013 运维系列——解决多域名同用户的配置问题
- [leetcode] 199. Binary Tree Right Side View
- hdu2082找单词(母函数)
- 【Android游戏开发十四】深入Animation,在SurfaceView中照样使用Android—Tween Animation!
- PTC_Mathcad Prime3.0 矩阵的运算
- uva-10921
- ROS在多机器人上的运行
- 2015年12月8日日志
- js判断MAC地址