【Android基础】多线程

本文详细介绍了Android中多线程的使用,包括为何使用多线程避免主线程阻塞,重点讲解了Handler的异步消息处理机制,包括Handler的常用方法、Message属性以及如何避免内存泄漏。同时,还探讨了AsyncTask的使用,如其三个泛型的意义和执行的四个步骤,以及如何启动和停止异步任务。
摘要由CSDN通过智能技术生成

一、为什么使用多线程

Android中主线程不能执行耗时操作、不能访问网络等。这些动作会导致主线程被阻塞,容易引起ANR(Application no response)异常。
所以必须把访问网络、耗时操作等放入到子线程中执行。Android的主线程(UI线程)是线程不安全的,所以当各个子线程获得数据之后不能直接修改UI,必须把修改UI的权利交给主线程。

二、异步消息处理机制——Handler

Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper。

  • Looper
    每一个线程只有一个Looper对象。每个线程在初始化Looper之后,Looper会维护好该线程的MessageQueue。MessageQueue用来存放Handler发送的Message,并处理MessageQueue中的Message。
    当我们在主线程创建Handler时,它就会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。
    非主线程没有loop对象,所以要调用Looper.prepare()方法。
  • MessageQueue
    MessageQueue是一个消息队列,用来存放Handler发送的消息。每个线程最多只有一个MessageQueue。
    MessageQueue通常都是由Looper来管理。
  • Message
    被传递和处理的数据。其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
    一个MessageQueue可以包括多个Message。
    Message虽然也可以通过new来获取,但是通常使用Message.obtain()或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源。
  • Handler
    负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

子线程中使用Handler的步骤:

        new Thread(new Runnable() {
   
            @Override
            public void run() {
   
                //1、为子线程创建一个Looper
                Looper.prepare();
                //2、创建Handler对象
                Handler handler = new Handler() {
   
                    @Override
                    public void handleMessage(@NonNull Message msg) {
   
                        super.handleMessage(msg);
                    }
                };
                //3、调用Looper.loop()
                //在线程中调用过Looper.loop()之后,后面不能再写代码,因为loop()内部是个死循环,后面的写的代码无法执行到。
                Looper.loop();
            }
        }).start();

1、Handler类中常用方法

1)sendEmptyMessage(int what)

发送一条空消息

2)sendEmptyMessageDelayed(int what, long delayMillis)

在该方法内部首先将what封装成一个Message,同时调用sendMessageDelayed(msg, delayMillis)方法延迟发送一条消息

3)sendMessageDelayed(Message msg, long delayMillis)

表示延迟发送一条消息

4)sendMessageAtTime(Message msg, long uptimeMillis)

方法表示定时发送一条消息

5)handleMessage(Message msg)

对Handler发送来的消息进行处理

6)post(Runnable r)

发送一个子线程

7)postDelayed(Runnable r, long delayMillis)

延迟发送一个子线程

8)obtainMessage()

从消息池中获得一个消息

2、Message消息类中常用属性

arg1:用来存放整型数据
arg2:用来存放整型数据
obj:用来存放Object数据
what:用于指定用户自定义的消息代码,这样便于主线程接收后,根据消息代码不同而执行不同的相应操作

3、Handler造成内存泄漏

1)原因
    private Handler handler = new Handler() {
   
        @Override
        public void handleMessage(@NonNull Message msg) {
   
            super.handleMessage(msg);
            textView.setText(msg.what + "");
        }
    };

上面是一段简单的Handler的使用。
非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,当一个对象一句不需要再使用了,本来该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏(上面的例子就是这个原因)。

2)解决方案

方法一:通过程序逻辑来进行保护。
1)在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2)如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。
方法二:将Handler声明为静态类。
在Java 中,非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,静态的内部类不会持有外部类的引用。
静态类不持有外部类的对象,所以你的Activity可以随意被回收。由于Handler不再持有外部类对象的引用,导致程序不允许在Handler中操作Activity中的对象了。所以需要在Handler中增加一个对Activity的弱引用(WeakReference)。

  • 步骤一
    创建静态内部类
  • 步骤二
    对Activity的弱引用(WeakReference)
  • 步骤三
    handleMessage方法中对Handler发送来的消息进行处理
    //1、创建静态内部类
    private static class MyHandler extends Handler {
   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值