深入Android Handler与线程间通信ITC的详解

在《Android Handler之消息循环的深入解析》中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间通信ITC,这种方式更加安全和高效,可以大大减少同步的烦恼,甚至都可以不用syncrhonized。
线程间通讯ITC
正常情况下函数调用栈都会生存在同一个线程内,想要把执行逻辑交换到其他线程可以新建一个Thread,然后start()。另外一种方法就是用ITC,也即用消息队列来实现,线程需要把执行逻辑交到其他线程时就向另外的线程的消息队列发送一个消息,发送消息后函数就此结束返回,调用栈也停止。当消息队列中有了消息时,线程会被唤醒来执行处理消息,从而把执行逻辑从一个线程转到另外一个线程。这就实现了线程间的通信ITC,与进行间通讯IPC有十分类似的思想。

通常的做法都是,在主线程创建一个Handler,然后在新建线程中使用此Handler与主线程通讯。因为主线程的消息队列已经建好,所以直接创建Handler即可,新建的线程就可以直接使用。
有些情况,需要在多线程之间进行通信,这就要为每个线程都创建MessageQueue和Handler,只要线程能访问其他线程的Handler就可以与之通信。

要正确的创建Handler,因为Handler要与线程绑定,所以在初始化Handler的时候就要注意:
如果给Handler指定Looper对象new Handler(Looper),那么此Handler便绑定到Looper对象所在的线程中,Handler的消息处理回调会在那个线程中执行。
如果创建线程时不指定Looper对象,那么此Handler绑定到创建此Handler的线程内,消息回调处理会在那个线程中执行,所以像下面的例子,如果这样写:


代码如下:

private class CookServer extends Thread {
       private Handler mHandler = new Handler() {
               public void handleMessage(Message msg) {
                     ....
                }
        };

那么,此mHandler会与创建此CookerServer的线程绑定,handleMessage也会运行于其中。显然,如果是主线程调用new CookServer(),那么mHandler其实是运行在主线程中的。正确的写法应该是:


代码如下:

private class CookServer extends Thread {
       public void run() {
             Looper.prepare();
                 // or new Handler(Looper.myLooper())
                 private Handler mHandler = new Handler() {
                       public void handleMessage(Message msg) {
                     ....
                }
        };

HandlerThread
如果要在一个线程中使用消息队列和Handler,Android API中已经有封装好了的一个类HandlerThread,这个类已经做好了Looper的初始化工作,你需要做的就是重写其onLooperPrepared()方法,在其中创建Handler:


代码如下:

private class DeliverServer extends HandlerThread {
      private Handler mHandler;
      public DeliverServer(String name) {
           super(name);
      }
      @Override
      public void onLooperPrepared() {
            mHandler = new Handler(getLooper()) {
                    public void handleMessage(Message msg) {
                        .....
                    }
             };
       }
}

实例
此实例模拟了一个网络订餐系统,客户点击“Submit order"来产生一个定单,主线程中负责收集定单,然后交由CookServer来制作,CookServer在制作完成后会交由DeliverServer来把食物运送到客户,至此一个定单完成,同时CookServer和DeliverServer会更新状态。




代码如下:

/**
 * How to attach an Handler to a Thread:
 * If you specify Looper object to Handler, i.e. new Handler(Looper), then the handler is attached to the thread owning
 * the Looper object, in which handleMessage() is executed.
 * If you do not specify the Looper object, then the handler is attached to the thread calling new Handler(), in which
 * handleMessage() is executed.
 * In this example, for class CookServer or DeliverServer, if you write this way:
 *     private class CookServer extends Thread {
  private Handler mHandler;
  private Looper mLooper;

public CookServer() {
   mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
     ....
    }
       start();
  }
 * then mHandler is attached to thread calling new CookServer(), which is the main thread, so mHandler.handleMessage() will
 * be executed in main thread.
 * To attach mHandler to its own thread, you must put it in run(), or after mLooper is created. For our example, providing
 * mLooper or not won't matter, because new Handler() is called in run(), which is in a new thread.
 */
public class HandlerITCDemo extends ListActivity {
    private static final int COOKING_STARTED = 1;
    private static final int COOKING_DONE = 2;
    private static final int DELIVERING_STARTED = 3;
    private static final int ORDER_DONE = 4;

private ListView mListView;
    private static final String[] mFoods = new String[] {
 "Cubake",
 "Donut",
 "Eclaire",
 "Gingerbread",
 "Honeycomb",
 "Ice Cream Sanwitch",
 "Jelly Bean",
    };
    private ArrayList<String> mOrderList;
    private TextView mGeneralStatus;
    private Button mSubmitOrder;
    private static Random mRandomer = new Random(47);
    private int mOrderCount;
    private int mCookingCount;
    private int mDeliveringCount;
    private int mDoneCount;

private Handler mMainHandler = new Handler() {
 @Override
 public void handleMessage(Message msg) {
     switch (msg.what) {
     case COOKING_STARTED:
  mCookingCount++;
  break;
     case COOKING_DONE:
  mCookingCount--;
  break;
     case DELIVERING_STARTED:
  mDeliveringCount++;
  break;
     case ORDER_DONE:
  mDeliveringCount--;
  mDoneCount++;
     default:
  break;
     }
     mGeneralStatus.setText(makeStatusLabel());
 }
    };

private CookServer mCookServer;
    private DeliverServer mDeliverServer;

@Override
    protected void onDestroy() {
 super.onDestroy();
 if (mCookServer != null) {
     mCookServer.exit();
     mCookServer = null;
 }
 if (mDeliverServer != null) {
     mDeliverServer.exit();
     mDeliverServer = null;
 }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 mListView = getListView();
 mOrderList = new ArrayList<String>();
 mGeneralStatus = new TextView(getApplication());
 mGeneralStatus.setText(makeStatusLabel());
 mSubmitOrder = new Button(getApplication());
 mSubmitOrder.setText("Submit order");
 mSubmitOrder.setOnClickListener(new View.OnClickListener() {
     public void onClick(View v) {
  String order = mFoods[mRandomer.nextInt(mFoods.length)];
  mOrderList.add(order);
  mOrderCount = mOrderList.size();
  mGeneralStatus.setText(makeStatusLabel());
  setAdapter();
  mCookServer.cook(order);
     }
 });
 mListView.addHeaderView(mGeneralStatus);
 mListView.addFooterView(mSubmitOrder);
 setAdapter();
 mCookServer = new CookServer();
 mDeliverServer = new DeliverServer("deliver server");
    }

private String makeStatusLabel() {
 StringBuilder sb = new StringBuilder();
 sb.append("Total: ");
 sb.append(mOrderCount);
 sb.append("    Cooking: ");
 sb.append(mCookingCount);
 sb.append("    Delivering: ");
 sb.append(mDeliveringCount);
 sb.append("    Done: ");
 sb.append(mDoneCount);
 return sb.toString();
    }

private void setAdapter() {
 final ListAdapter adapter = new ArrayAdapter<String>(getApplication(), android.R.layout.simple_list_item_1, mOrderList);
 setListAdapter(adapter);
    }

private class CookServer extends Thread {
 private Handler mHandler;
 private Looper mLooper;

public CookServer() {
     start();
 }

@Override
 public void run() {
     Looper.prepare();
     mLooper = Looper.myLooper();
     mHandler = new Handler(mLooper, new Handler.Callback() {
  public boolean handleMessage(Message msg) {
      new Cooker((String) msg.obj);
      return true;
  }
     });
     Looper.loop();
 }

public void cook(String order) {
     if (mLooper == null || mHandler == null) {
  return;
     }
     Message msg = Message.obtain();
     msg.obj = order;
     mHandler.sendMessage(msg);
 }

public void exit() {
     if (mLooper != null) {
  mLooper.quit();
  mHandler = null;
  mLooper = null;
     }
 }
    }

private class Cooker extends Thread {
 private String order;
 public Cooker(String order) {
     this.order = order;
     start();
 }

@Override
 public void run() {
            mMainHandler.sendEmptyMessage(COOKING_STARTED);
            SystemClock.sleep(mRandomer.nextInt(50000));
            mDeliverServer.deliver(order);
            mMainHandler.sendEmptyMessage(COOKING_DONE);
 }
    }

private class DeliverServer extends HandlerThread {
 private Handler mHandler;

public DeliverServer(String name) {
     super(name);
     start();
 }

@Override
 protected void onLooperPrepared() {
     super.onLooperPrepared();
     mHandler = new Handler(getLooper(), new Handler.Callback() {
  public boolean handleMessage(Message msg) {
      new Deliver((String) msg.obj);
      return true;
  }
     });
 }
 public void deliver(String order) {
     if (mHandler == null || getLooper() == null) {
  return;
     }
     Message msg = Message.obtain();
     msg.obj = order;
     mHandler.sendMessage(msg);
 }

public void exit() {
     quit();
     mHandler = null;
 }
    }

private class Deliver extends Thread {
 private String order;
 public Deliver(String order) {
     this.order = order;
     start();
 }

@Override
 public void run() {
     mMainHandler.sendEmptyMessage(DELIVERING_STARTED);
     SystemClock.sleep(mRandomer.nextInt(50000));
     mMainHandler.sendEmptyMessage(ORDER_DONE);
 }
    }
}

(0)

相关推荐

  • Android中的Handler与多线程应用实例

    本文首先解释一下handler是用来干嘛的,然后通过例子介绍其在多线程中的应用. 什么是Handler handler通俗一点讲就是用来在各个进程之间发送数据的处理对象.在任何进程中,只要获得了另一个进程的handler则可以通过handler.sendMessage(message)方法向那个进程发送数据.基于这个机制,我们在处理多线程的时候可以新建一个thread,这个thread拥有UI线程中的一个handler.当thread处理完一些耗时的操作后通过传递过来的handler像ui线程发

  • android使用handlerthread创建线程示例

    在android开发中,一说起线程的使用,很多人马上想到new Thread(){...}.start()这种方式.这样使用当然可以,但是多次使用这种方式,会创建多个匿名线程.使得程序运行起来越来越慢.因此,可以考虑使用一个Handler来启动一个线程,当该线程不再使用就删除,保证线程不会重复创建.一般会使用Handler handler = new Handler(){...}创建Handler.这样创建的handler是在主线程即UI线程下的Handler,即这个Handler是与UI线程下

  • android使用handler ui线程和子线程通讯更新ui示例

    复制代码 代码如下: package com.act262.sockettx; import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import and

  • Handler与Android多线程详解

    下面是一段大家都比较熟悉的代码: 复制代码 代码如下: Handler handler = new Handler(); handler.post(myThread); //使用匿名内部类创建一个线程myThreadRunnable mythread = new Runnable() {public void run() {}}; 一开始,相信很多人都以为myThread中的run()方法会在一个新的线程中运行,但事实并非如此. 上述代码中的handler并没有调用线程myThread的star

  • 实例讲解Android多线程应用开发中Handler的使用

    其实可以理解Handler为主线程和另外的线程之间进行数据更新的东东,并且Handler在主线程中,并在Handler直接调用线程的run方法 package com.Handler02; import android.app.Activity; import android.os.Bundle; import android.os.Handler; public class Handler02Activity extends Activity { /** Called when the act

  • Android Handler主线程和一般线程通信的应用分析

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

  • Android编程实现使用handler在子线程中更新UI示例

    本文实例讲述了Android编程实现使用handler在子线程中更新UI.分享给大家供大家参考,具体如下: MainActivity代码: package com.example.ui; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextV

  • Android多线程处理机制中的Handler使用介绍

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

  • Android Handler多线程详解

    Android--多线程之Handler 前言 Android的消息传递机制是另外一种形式的"事件处理",这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的UI组件,这样会导致新启动的线程无法改变UI组件的属性值.但实际开发中,很多地方需要在 工作线程中改变UI组件的属性值,比如下载网络图片.动画等等.本篇博客主要介绍Handler是如何发送与处理线程上传递来的消息,并讲解 Message的几种传递数

  • Android App在线程中创建handler的方法讲解

    相关概念 1.Handler:可以看做是一个工具类,用来向消息队列中插入消息的; 2.Thread:所有与Handler相关的功能都是与Thread密不可分的,Handler会与创建时所在的线程绑定; 3.Message:消息; 4.MessageQueue:消息队列,对消息进行管理,实现了一个Message链表; 5.Looper:消息循环,从MessageQueue中取出Message进行处理: 6.HandlerThread:继承Thread,实例化时自动创建Looper对象,实现一个消息

随机推荐