android中的Handler和Runnable

最近在做一个项目,在网络请求时考虑用Handler进行处理,然后就研究了一下Handler和Runnable

首先在看一下java中的Runnable

The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run.

This interface is designed to provide a common protocol for objects that wish to execute code while they are active. For example, Runnable is implemented by class Thread. Being active simply means that a thread has been started and has not yet been stopped.

In addition, Runnable provides the means for a class to be active while not subclassing Thread. A class that implements Runnable can run without subclassing Thread by instantiating a Thread instance and passing itself in as the target. In most cases, the Runnable interface should be used if you are only planning to override the run() method and no other Thread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.

这个官方文档中的描述,看原版文档还是很有好处的,就不翻译了。

在Java中Runnable可以实现资源共享的多线程,网上多拿卖票的例子来讲,但是看上去有点模糊不清,对于这样一个代码

MyRunnable runnable = new MyRunnable;
new Thread(runnable,"a").start();
new Thread(runnable,"b").start();

它们之间资源共享到底是怎么个共享呢?

现在我们来看一下例子

public class Main {

    public static void main(String[] args)  {
        new Main().test();
    }

    void test(){
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable,"a").start();
        new Thread(runnable,"b").start();
    }
    public class MyRunnable implements Runnable{
        @Override
        public void run() {
            for (int i=0;i<5;i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
        }

    }
}

执行结果

a0
b0
b1
b2
b3
b4
a1
a2
a3
a4

可以看到这两个线程相互之间并没有影响得都执行了5次

然后在我们的Runnable类里边加一个全局变量

public class Main {

    public static void main(String[] args)  {
        new Main().test();
    }

    void test(){
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable,"a").start();
        new Thread(runnable,"b").start();
    }

    public class MyRunnable implements Runnable{
        int num=0;
        @Override
        public void run() {
            for (int i=0;i<5;i++) {
                ++num;
                System.out.println(Thread.currentThread().getName() + i+"--------"+num);
            }
        }
    }
}

执行结果

b0--------2
b1--------3
a0--------2
b2--------4
a1--------5
b3--------6
a2--------7
b4--------8
a3--------9
a4--------10

可以发现这个全局变量是在两个线程之间共享的

这说明什么?当一个Runnable对象传递到多个线程执行时,Runnable对象的run()方法会在多个线程中执行,而全局变量是在这些线程中共享的

因此,我们可以通过一个全局变量充当线程锁比如:

public class Main {

    public static void main(String[] args)  {
        new Main().test();
    }

    void test(){
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable,"a").start();
        new Thread(runnable,"b").start();
    }

    public class MyRunnable implements Runnable{
        int num=0;
        final  String string ="";
        @Override
        public void run() {
            synchronized (string){
                for (int i=0;i<5;i++) {
                    ++num;
                    System.out.println(Thread.currentThread().getName() + i+"--------"+num);
                }
            }
        }
    }
}

这样的执行结果

a0--------1
a1--------2
a2--------3
a3--------4
a4--------5
b0--------6
b1--------7
b2--------8
b3--------9
b4--------10

这样只有当一个线程中的run()方法执行完之后才会执行另一个

然后把同步锁的地方变一下

public class Main {

    public static void main(String[] args) {
        new Main().test();
    }

    void test() {
        MyRunnable runnable = new MyRunnable();
        new Thread(runnable, "a").start();
        new Thread(runnable, "b").start();
    }

    public class MyRunnable implements Runnable {
        int num = 0;
        final String string = "";
        @Override
        public void run() {
            for (int i = 0; i < 5; i++) {
                synchronized (string) {
                    ++num;
                    System.out.println(Thread.currentThread().getName() + i + "--------" + num);
                }
            }
        }
    }
}

执行结果

a0--------1
b0--------2
b1--------3
b2--------4
b3--------5
b4--------6
a1--------7
a2--------8
a3--------9
a4--------10

可以看到,两个线程交替执行,但只有一个线程的

++num;

System.out.println(Thread.currentThread().getName() + i + "--------" + num);

执行完之后才会执行另一个线程的,所以全局变量的值是依次增加的。



再来看Android中的Handler的post(Runnale)这个方法

public class MainActivity extends AppCompatActivity {

    Handler handler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyRunnable myRunnable = new MyRunnable();
        handler.post(myRunnable);
    }

    class MyRunnable implements  Runnable{
        @Override
        public void run() {
            for (int i=0;i<5;++i){
                System.out.println(Thread.currentThread().getName()+"---"+i);
            }
        }
    }
}

可以看到,这个Runnable实在主线程上运行的,因为Handler是在主线程上创建的,与主线程绑定。一些新手可能就会以为这样是新建了一个线程,把耗时操作放里边造成UI卡顿。api说明如下:

Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.

那么我们post两个呢,代码修改为

MyRunnable myRunnable = new MyRunnable();
handler.post(myRunnable);
handler.post(myRunnable);

那相应的结果

可以看到是依次运行的,这也体现了Handler的消息队列的思想

再改一下

MyRunnable myRunnable = new MyRunnable();
handler.post(myRunnable);
handler.post(myRunnable);
System.out.println("post finish");

可以看到在post之后并不是立即执行。

那么如何post一个runnable对象到子线程执行呢?这就要将Handler与一个子线程绑定

public class MainActivity extends AppCompatActivity {

    HandlerThread thread = new HandlerThread("subThread");
    Handler handler = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        thread.start();
        handler = new Handler(thread.getLooper());
        MyRunnable myRunnable = new MyRunnable();
        handler.post(myRunnable);
        System.out.println("post finish");
    }

    class MyRunnable implements  Runnable{
        @Override
        public void run() {
            for (int i=0;i<5;++i){
                System.out.println(Thread.currentThread().getName()+"---"+i);
            }
        }
    }
}

执行结果:

时间: 2024-08-24 11:00:09

android中的Handler和Runnable的相关文章

Android中的Handler, Looper, MessageQueue和Thread

Android中的Handler, Looper, MessageQueue和Thread 前几天,和同事探讨了一下Android中的消息机制,探究了消息的发送和接收过程以及与线程之间的关系.虽然我们经常使用这些基础的东西,但对于其内部原理的了解,能使我们更加容易.合理地架构系统,并避免一些低级错误. 对于这部分的内容,将分成4小节来描述: 1.职责与关系 2.消息循环 3.线程与更新 4.几点小结 ------------------------------------------------

Android中的Handler

当我们在处理下载或是其他需要长时间执行的任务时,如果直接把处理函数放在Activity的OnCreate或是OnStart中,会导致执行过程中整个Activity无响应,如果时间过长,程序就会挂掉.Handler就是把这些功能放到一个当初的线程里执行,与Activity互不影响. 一.Handler的定义:  Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中来接收.处理该消

深入源码解析Android中的Handler,Message,MessageQueue,Looper

本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文< Android中Handler的使用>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但

Android中的Handler的具体用法

Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.Android利用Handler来实现UI线程的更新的. Handler是Android中的消息发送器,其在哪个Activity中创建就属于且紧紧属于该Activity.还可以说其在哪个线程中new的,就是那个线程的Handler. Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的U

Android中使用Handler造成内存泄露的分析和解决

什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收:另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收. Android中使用Handler造成内存泄露的原因 Handler mHand

Android中利用Handler实现消息的分发机制(三)

在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而如果在子线程中需要去使用Handler的时候,我们就需要显式地去调用Looper的 prepare方法和loop方法,从而为子线程创建其唯一的Looper. 具体代码如下: class LooperThread extends Thread { public Handler mHandler; public void run()

Android中的Handler的机制与用法详解

概述: 很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制, 在Android系统中实现了一套类似的消息处理机制.在下面介绍handler机制前,首先得了解以下几个概念:     1. Message 消息,理解为线程间通讯的数据单元.例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程.     2. Message Queue 消息队列,用来存放通过Handler发布的消息,按照先

android中的Handler和Callback机制

android中的Handler和Callback机制 - - ITeye技术网站 Handler主要用来在线程之间的通信的机制.如在Activity或Service中需要接受其他线程的消息,则在需要接收消息的Activity或Service中需要实现Handler.Callback接口,实现这个接口的: Java代码 ? public?boolean?handleMessage(?Message?inMessage?)?:?? public boolean handleMessage( Mes

Android中关于Handler的总结

一.Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI.          解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作.  如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象,