对Handler的学习和理解

我对Handler的学习和理解

今天花了点时间研究了一下Handler的细节,来做一下总结:

  • Handler的基本用法
  • Handler的大致实现机制
  • 防止内存泄漏的优化

Handler的基本用法

当我们在初学安卓的时候,就听说过一句话:“耗时操作要放在子线程中,更改UI操作要放在主线程中”,为什么呢?因为如果在主线程中出现耗时操作,那么我们的应用便会出现无响应的情况,这样会造成用户的使用体验变差,而且应用如果出现那么我们如果遇到这样的情况:**当我们在加载资源的时候,这个加载的操作是耗时操作需要放在子线程中,我们加载完成后,需要告诉主界面,数据已经加载完成了,我们现在可以把资源显示在主界面上了,但是我们又不能在子线程中对界面进行修改,那么该怎么办呢?**这时我们就可以使用Handler来帮我们解决问题。

public class MainActivity extends AppCompatActivity {

    private static final int DOWNLAND_OVER = 1;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case DOWNLAND_OVER:
                    Toast.makeText(MainActivity.this,"加载完成了",Toast.LENGTH_SHORT).show();
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //耗时操作
                    Thread.sleep(3000);

                    Message message;
                    if(Message.obtain()!=null){
                        message = Message.obtain();
                    }else{
                        message = new Message();
                    }
                    message.what = DOWNLAND_OVER;
                    handler.sendMessage(message);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

这里我使用了Thread.sleep(3000);来模拟加载的耗时操作,用Toast来模拟改变界面的操作,这样便可以达到子线程中通知主线程修改UI的操作。

Handler的大致实现机制

讲Handler的实现机制,便要涉及到Looper,Handler,Message,MessageQueue这四个工具。
看上面的代码,首先,我们创建了一个Message的实例,我们可以把这个类理解成为一个消息,当我们在子线程中把耗时操作执行完以后,便创建一个消息,告诉主线程来对UI进行修改。那么,告诉的这个动作便由Handler来执行,handler.sendMessage(message),这个函数把消息发了出去,最后由handleMessage(Message msg)这个函数接收了消息,并对消息进行处理。大致就是这样的一个过程。
MessageQueue这个类是用来储存Message的集合,内部使用的是单链表的方式储存Message,Looper可以理解成为一个环,这个环里面是一个死循环,来不断地对MessageQueue里的内容进行提取,提取出来以后,再将message给handler进行处理。
handler的消息处理机制大致就是这样的。

##防止内存泄漏的优化
接下来讲一下Handler的内存泄漏的风险,看上面的代码,其实我写的是很有问题的。问题在哪里呢?
我们在创建内部类的时候,内部类会隐式地与外部类进行关联,持有外部类的引用,这样会导致一个问题,当我们Activity关闭时,handler理应也关闭,但是如果此时还有message未被处理,便会使得Activity无法被回收,就会出现内存泄漏的问题
那么我们如何来解决这个问题呢?
把handler定义成静态变量,并使用弱引用
们可以把handler定义成static类型,利用弱引用来对Activity1里的控件进行操作

static class MyHandler extends Handler{
    WeakReference<Activity1> weakreference;
     Activity1 mainactivity;
    public MyHandler(Activity1activity){
        weakreference = new WeakReference<Activity1>(activity);
        mainactivity = weakreference.get();
    }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case DOWNLAND_OVER:
                    if(weakreference.get()!=null){
                     Toast.makeText(mainactivity,"加载完成了",Toast.LENGTH_SHORT).show();  
                    Intent intent= new Intent(mainactivity,Activity2.class);}
            }
        }
    }

    MyHandler myhandler;

当GC碰到弱引用指向的实例时,一定会回收此实例,所以当Acivity被回收的时候,GC判断此时没有强引用指向Activity,只有弱引用,便会回收这个Activity实例。静态方法会让MyHandler类独立于外部的Activity,并且在处理Message时,判断弱引用是否被回收,如果被回收,就放弃执行代码。
这样我们就可以避免内存泄漏的问题了。
当然,我们的目的不仅仅是为了防止内存泄漏,更重要的是要逻辑业务的顺利执行,所以我们在买保险的同时,更重要的是对代码的审核和思考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值