您的位置:首页 > 其它

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秒(主程序设定)后,会返回到下一个业务界面。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: