Android开发关于Handler不太容易理解的几个知识点(post,runOnUiThread,Handler内存泄漏使用弱引用解决)

Android开发Handler中为什么会使用到弱引用:

主要是解决Handler内存泄漏问题。什么是Handler内存泄漏?

当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用,不然你怎么可能通过Handler来操作Activity中的View。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。

然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。

如果一个内存中的对象没有任何引用的话,就说明这个对象已经不再被使用了,从而可以成为被垃圾回收的候选。不过由于垃圾回收器的运行时间不确定,可被垃圾回收的对象的实际被回收时间是不确定的。对于一个对象来说,只要有引用的存在,它就会一直存在于内存中。如果这样的对象越来越多,超出了JVM中的内存总数,JVM就会抛出OutOfMemory错误。虽然垃圾回收的具体运行是由JVM来控制的,但是开发人员仍然可以在一定程度上与垃圾回收器进行交互,其目的在于更好的帮助垃圾回收器管理好应用的内存。

以上先介绍弱引用的概念,下面讲解Handler在实际开发中的几种使用情况:

先理解概念:在Android开发中,为了UI操作是线程安全的,规定只允许UI线程更新Activity中的UI组件(如果不这样规定的话,试想一下,一个Activity中可以开启好多线程,如果这些线程都可以有权利更新UI组件,而不遵守调度机制等规则,那么界面该是有多混乱,可能前一秒TextView的内容是这样,而后一秒则变成那样)。但是在实际开发过程中,总是存在着这样的问题:有许多子线程需要对UI主线程中的组件进行操作,那么问题就出现了:怎么才能保证多个线程能够并发操作UI组件,并且能够保证线程安全呢?这就需要使用到Handler消息机制了,即工作线程需要更新UI组件的时候,通过Handler通知主线程,从而在主线程中执行UI操作。

总结起来使用Handler的原因就是:将工作线程需操作UI的消息 传递 到主线程,使得主线程可根据工作线程的需求 更新UI从而避免线程操作不安全的问题。

1,下面使用post()方法来执行Handler操作:

public class MainActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.button_1);
        textView=findViewById(R.id.text_view);
        handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("这是使用post方式改变组件");
                    }
                });
            }
        });


    }
}

2,使用runOnUiThread:(在主线程)

public class MainActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.button_1);
        textView=findViewById(R.id.text_view);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("这是使用runOnUiThread来改变");
                    }
                });
            }
        });


    }
}

在子线程


public class MainActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.button_1);
        textView=findViewById(R.id.text_view);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               new Thread(new Runnable() {
                   @Override
                   public void run() {
                       runOnUiThread(new Runnable() {
                           @Override
                           public void run() {
                               textView.setText("这是使用runOnUiThread来改变");
                           }
                       });
                   }
               }).start();
            }
        });


    }
}

3,发送延迟消息,下面这个例子就是在2秒后发送消息:


public class MainActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    textView.setText("这是使用延迟");
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.button_1);
        textView=findViewById(R.id.text_view);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               new Thread(new Runnable() {
                   @Override
                   public void run() {
                       handler.sendEmptyMessageDelayed(1,2000);
                   }
               }).start();
            }
        });


    }
}

1,使用静态内部类来解决内存泄漏


import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.lang.ref.WeakReference;

public class SampleActivity extends AppCompatActivity {


    private final MyHandler mHandler = new MyHandler(this);

    private static final Runnable sRunnable = new Runnable() {
        @Override
        public void run() {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
        finish();
    }


    static class MyHandler extends Handler {
        private final WeakReference<SampleActivity> mActivity;
        public MyHandler(SampleActivity activity) {
            mActivity = new WeakReference<SampleActivity>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            SampleActivity activity = mActivity.get();
            if (activity != null) {


            }
        }
    }

}

 

 

 


关于android Handler为什么要使用弱引用请看下面一篇博客:https://blog.csdn.net/qq_38684229/article/details/80931865

虽然觉得自己handler掌握的差不多了,但是读完这两位大神的文章,对是觉得受益匪浅,推荐给大家。

Android Handler消息机制原理最全解读(持续补充中)https://blog.csdn.net/wsq_tomato/article/details/80301851

手把手带你分析Handler机制源码https://www.jianshu.com/p/b4d745c7ff7a

在学习Handler之前需要了解一下java弱引用,这里也有一篇博客,大家可以参考一下:

java四种引用      https://www.cnblogs.com/fengbs/p/7019687.html

 

 

 

 

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值