在子线程中创建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三个组合起来,和线程池特别类似,可以利用此,维护一个类似与线程池的框架,用来处理耗时多线程操作,比如网络下载多个图片等
时间: 2024-12-21 03:50:25

在子线程中创建Handler和looper并与主线程进行交互的相关文章

转 在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()

在子线程中new一个Handler为什么会报以下错误? java.lang.RuntimeException:  Can't create handler inside thread that has not called Looper.prepare()  这是因为Handler对象与其调用者在同一线程中,如果在Handler中设置了延时操作,则调用线程也会堵塞.每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue).如果在创建Ha

子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次, 接着再回到主线程又循环 100,如此循环 50 次

子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次, 接着再回到主线程又循环 100,如此循环 50 次 1 package TestThread; 2 3 /** 4 * 子线程循环 10 次, 接着主线程循环 100, 接着又回到子线程循环 10 次, 接着再回到主线程又循环 100, 如此循环 50 次 5 * 6 * @author trfizeng 7 * 8 */ 9 public class ThreadTest { 10 static int round

子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程循环100次,如此循环50次-004

子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程循环100次,如此循环50次 public class Sub10Main100Loop50Thread { public static void main(String[] args) throws InterruptedException { Business business = new Business(); new Thread(new Runnable(){ @Override public voi

在子线程中创建新的窗体,遇到的问题。

场景: 服务端的应用程序创建了一个线程来接收客户端发来的消息,当接收到消息后,需要弹出一个新的窗体,作为响应操作等. 现象: 新创建的窗体呈现挂起.假死,或者一闪而过的现象. 原因: 新创建的响应窗体是由子线程创建的,而.net平台下,子线程执行完毕后,会自动释放资源,同样的,这个新创建的窗体也会被释放掉.若是这个线程处于监听或者一些其他的连续执行状态,那么,这个窗体就会出现假死状态. 解决方案: 可以在子线程中调用一个代码段,而这个代码段通过invoke方法回答主线程中去创建和现实Form2,

C# 在子线程中创建不会阻塞执行窗体

可以参考”C# 对 Windows 窗体控件进行线程安全调用“一文来看. 在做网络连接程序的时候碰到一个问题:每当连接到来时,都创建一个新的接收线程,而该接收线程在接收到消息时,可以创建一个新的对话窗口,而该窗口不能阻塞该接收线程的下一轮消息的接收,而且该接收线程还要把接收到的消息显示在该窗口上 Form.ShowDialog();方法弹出模态对话框,而模态对话框会阻塞后面代码的执行,导致接收线程无法继续执行(除非该模态窗口被关闭) 刚开始想到的解决办法,就是:通过Form.Show();方法,

Android在线程中发送GET和POST请求 在主线程更新UI

public class GetPostUtil { /** * 向指定URL发送GET方法的请求 * * @param url * 发送请求的URL * @param params * 请求参数,请求参数应该是name1=value1&name2=value2的形式. * @return URL所代表远程资源的响应 */ public static String sendGet(String url, String params) { String result = "";

Android中Handler的使用方法——在子线程中更新界面

本文主要介绍Android的Handler的使用方法.Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列.每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联. Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器.2)线程间通信.在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息.当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Han

android 不能在子线程中更新ui的讨论和分析

问题描述 做过android开发基本都遇见过ViewRootImpl$CalledFromWrongThreadException,上网一查,得到结果基本都是只能在主线程中更改ui,子线程要修改ui只能post到主线程或者使用handler之类.但是仔细看看exception的描述并不是这样的,"Only the original thread that created a view hierarchy can touch its views",只有创建该 view 布局层次的原始线程

Android--Handler的使用方法:在子线程中更新界面

本文主要介绍Android的Handler的使用方法.Handler可以发送Messsage和Runnable对象到与其相关联的线程的消息队列.每个Handler对象与创建它的线程相关联,并且每个Handler对象只能与一个线程相关联. Handler一般有两种用途:1)执行计划任务,你可以再预定的实现执行某些任务,可以模拟定时器.2)线程间通信.在Android的应用启动时,会创建一个主线程,主线程会创建一个消息队列来处理各种消息.当你创建子线程时,你可以再你的子线程中拿到父线程中创建的Han