zoukankan      html  css  js  c++  java
  • 在子线程中创建Handler和looper并与主线程进行交互

    分析完上面那篇文章,基本理解了handler的实现原理,乘热打铁,这里我们利用handler原理,在子线程中创建一个handler和looper

    可能很多面试时候问道,子线程中能不能new一个handler ?

    答案是可以的,但是因为主线程系统默认在ActivityThread中已将帮我们创建好一个looper和MessagQueue,我们不需要手动去创建

    (手动创建会出错,因为一个线程中默认只运行一个looper和MessageQueue,具体见ThreadLocal代码原理),

    而子线程中没有looper,我们必须学习ActivityThread中的代码手动创建一个Looper(MessageQueue不用创建,因为它在looper的构造方法中已经默认创建好了)

    1. 上代码,子线程类,里面维护了一个looper
      1.   

        import android.os.Handler;
        import android.os.Looper;
        import android.os.SystemClock;
        /**
        * 子线程looper所在的子线程类
        * @author Administrator
        *
        */
        public class MyLooperThread extends Thread {
        private Looper mLooper;
        int i=5;
        /**
        * MainActivity中handler
        */
        private Handler mHandler;
        /**
        * 构造方法接受主线程的Handler 方便用主线程的handler去发送消息给主线程的looper
        * @param mHandler
        */
        public MyLooperThread(Handler mHandler) {
        super();
        this.mHandler = mHandler;
        }
        private Handler looperThreadHandler=new Handler(){
        public void handleMessage(android.os.Message msg) {
        switch (msg.what) {
        case 1:
        System.out.println("主线程的消息来了....");
        break;

        
        

        default:
        //MyThread的线程发送一个0的消息, 执行一个耗时操作
        System.out.println("开始执行耗时操作....");
        SystemClock.sleep(2000);
        SystemClock.sleep(2000);
        if(i>0){
        i-=2;
        System.out.println("耗时操作已完下执行下一个....");
        //不断轮询执行
        looperThreadHandler.sendEmptyMessage(0);
        }else{
        //操作完成 发送消息到主线程
        mHandler.sendEmptyMessage(0);
        System.out.println("所有任务已完成,等待ing....");
        }
        break;
        }

        };
        };

        @Override
        public void run() {
        super.run();
        //初始化一个looper 其构造方法中默认已经
        Looper.prepare();
        synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
        }
        Looper.loop();
        System.out.println("执行了吗");

        }

        public Looper getmLooper() {
        return mLooper;
        }
        public Handler getHandler() {
        return looperThreadHandler;
        }
        public void setHandler(Handler handler) {
        this.looperThreadHandler = handler;
        }

        }

        上面的代码有点长,主要是创建了一个子线程类,然后在其run()方法里面创建一个looper并轮询,构造方法中接受一个主线程的handler,以便于耗时操作完成之后,利用这个handler发送消息给主线程,这里我们可以发现,要想向不同的线程中发消息,必须要获取向对应线程的handler,而handler在哪个线程创建的,就已经和当前线程绑定在一起了

    2. 第二个类 线程类 主要作用是用这个线程去向上面的looper线程发一个消息,启动它的耗时任务
      1.  
        /**
         * 线程类  在子线程中获取looper并发空消息
         * @author MR.wang
         *
         */
        public class MyThread extends Thread {
        
            MyLooperThread looperThread;
        
            public MyThread(MyLooperThread looperThread) {
                super();
                this.looperThread = looperThread;
            }
        
            @Override
            public void run() {
                super.run();
                looperThread.getHandler().sendEmptyMessage(0);
                System.out.println("子线程中的执行了吗");
            }
            
        
        }

        这个代码相对好理解些,构造方法中接受looper线程中的handler,以便给他发消息,最后在run()方法发个消息,启动looper线程的耗时任务.

    3. 第三个类,主线程的hanler所在的类
      1.  
        import android.app.Activity;
        import android.os.Bundle;
        import android.os.Handler;
        import android.widget.Toast;
        /**
         * 主线程类 
         * @author MR.wang
         */
        public class MainActivity extends Activity {
            private Handler handler = new Handler() {
                public void handleMessage(android.os.Message msg) {
                    //子线程执行耗时操作完成 通知主线程
                    Toast.makeText(MainActivity.this, "所有任务已完成", Toast.LENGTH_SHORT)
                            .show();
                    //获取子线程的handler并发送一个消息给子线程的looper
                    looperThread.getHandler().sendEmptyMessage(1);
                };
            };
            private MyLooperThread looperThread;
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                //初始化子线程中的looper
                looperThread = new MyLooperThread(handler);
                // 开启子线程中的looper
                looperThread.start();
                //初始化一个子线程 用于给looper所在的子线程发送消息启动它
                MyThread thread = new MyThread(looperThread);
                thread.start();
            }
        
        }

        着重看看onCreate方法,初始化一个looper线程,传入当前主线程的handler,然后让另外一个子线程去给looper线程发一个消息,执行耗时任务,looper线程中耗时任务执行完毕,拿着主线程传入的handler给主线程发个消息,最后主线程的handlMessage()方法收到消息,Toast出来,完成了主线程到子线程之间的消息对接

         
    4. 最后总结一下
      1. handler创建的时候,就与当前线程绑定起来,要给一个线程发消息,获取到此线程的hanler发送消息即可.
      2. 主线程中ActivityThread默认帮我们创建好了一个looper和MessageQueue,因此我们不需要手动创建,若需要在子线程中创建一个handler,则子线程中必须也有一个looper和MessageQueue与之对应,所有,子线程中可以有handler,只需我们手动创建一个looper即可(Messagequeue在looper构造方法中自动创建)
      3. 主线程的handlMessage中尽量不要执行任何耗时操作,因为容易造成主线程阻塞(UI线程5秒,服务10秒)
      4. handler looper Messagequeue三个组合起来,和线程池特别类似,可以利用此,维护一个类似与线程池的框架,用来处理耗时多线程操作,比如网络下载多个图片等
    静以修身 俭以养德
  • 相关阅读:
    ASP.NET 2.0的页面缓存功能介绍
    第五课 主定理
    HDU 1051 Wooden Sticks
    一行代码让浏览器变编辑器
    算法概论习题1001Forest
    第七课 寻找强连通分量
    8223. Tiling a Grid With Dominoes
    迷宫
    第八课 最小生成树之Kruskal
    解决 Ubuntu 12.04 无法调节屏幕亮度的问题
  • 原文地址:https://www.cnblogs.com/Android-MR-wang/p/4291391.html
Copyright © 2011-2022 走看看