最近在做毕设,关于android的,其中觉得android的消息机制很有意思,这里就写下自己的想法
和Windows一样android也是消息驱动的。Android通过Handler和looper实现消息循环机制。
一、Handler的创建
每个Handler都会和一个线程和线程的message queue关联起来,此时你可以传递messages 和 runnable对象到message queue中。后面可以从message queue中拿出该对象并且执行。
上面提到了Handler, Message queue这两个对象,那他们之间是怎么交互的呢?
这中间就涉及到了looper的概念。我们首先来看下handler和looper,message queue 这两个类的关系
Handler提供了很多的构造函数,
-
public Handler() {
-
mLooper = Looper.myLooper();
-
if (mLooper == null) {
-
throw new RuntimeException(
-
"Can't create handler inside thread that has not called Looper.prepare()");
-
}
-
mQueue = mLooper.mQueue;
-
mCallback = null;
-
}
-
-
public Handler(Looper looper) {
-
mLooper = looper;
-
mQueue = looper.mQueue;
-
mCallback = null;
-
}
从这两个构造函数中,我们发现当为提供looper的时候,android会通过Looper.myLooper()获得当前线程的looper。那通过myLooper()获得的当前线程的looper 可能会为 null 吗? 答案是肯定的,若在主线程下启动一个新的线程,那这个子线程是不会建立自己的Message Queue的。Android通过ActivityThread来启动一个activity,在activity的main()方法中有2句关键的代码
Looper. prepareMainLooper() //具体查看源代码
Looper.loop()
因为创建子线程的时候并没有运行前面这两句话,所以子线程中调用Looper.myLooper()返回的是null。所以就造成了在子线程中创default handler是错误的。而要在子线程中有自己的looper就需要如下写,
-
class LooperThread extends Thread {
-
public Handler mHandler;
-
-
public void run() {
-
Looper.prepare();
-
-
mHandler = new Handler() {
-
public void handleMessage(Message msg) {
-
// process incoming messages here
-
}
-
};
-
-
Looper.loop();
-
}
Looper源代码中有一个关键的方法prepare(),那他具体做什么事呢,代码如下
-
public static final void prepare() {
-
if (sThreadLocal.get() != null) {
-
throw new RuntimeException("Only one Looper may be created per thread");
-
}
-
sThreadLocal.set(new Looper());
-
}
通过ThreadLocal实现了一个线程只有一个Looper
二、Handler的消息发送
总感觉Handler就像一个交警一样,负责message的创建,获得,处理。Handler的sendMessage()方法最终其实就是调用了queue.enqueueMessage(msg, uptimeMillis);把消息放入message queue中。Looper通过Looper.loop()检测到有消息并将消息广播后,Handler又负责接收到此消息并调用handleMessage进行处理接下来的事情。Message的创建一般都是通过如下代码建立的,把Handler传进去
-
public final Message obtainMessage()
-
{
-
return Message.obtain(this);
-
}
三、Message
Message在里面是一个链表的结构。在这个方法中,会首先去MessagePool(消息回收站)去找Message,如果有被回收的Message,则会将这个Message取出来进行再利用。如果没有被回收的,这时系统才会真正new一个Message对象出来当然MessagePool不是无限大的,它最多只能保存十条回收的消息,多出来的就直接删除了
更新UI例子
-
public class ReviewList extends ListActivity {
-
-
private static final String CLASSTAG = ReviewList.class.getSimpleName();
-
private static final int MENU_CHANGE_CRITERIA = Menu.FIRST + 1;
-
private static final int MENU_GET_NEXT_PAGE = Menu.FIRST;
-
private static final int NUM_RESULTS_PER_PAGE = 8;
-
-
private TextView empty;
-
private ProgressDialog progressDialog;
-
private ReviewAdapter reviewAdapter;
-
private List<Review> reviews;
-
-
private final Handler handler = new Handler() {
-
@Override
-
public void handleMessage(final Message msg) {
-
Log.v(Constants.LOGTAG, " " + ReviewList.CLASSTAG + " worker thread done, setup ReviewAdapter");
-
progressDialog.dismiss();
-
if ((reviews == null) || (reviews.size() == 0)) {
-
empty.setText("No Data");
-
} else {
-
reviewAdapter = new ReviewAdapter(ReviewList.this, reviews);
-
setListAdapter(reviewAdapter);
-
}
-
}
-
};
-
-
@Override
-
public void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
Log.v(Constants.LOGTAG, " " + ReviewList.CLASSTAG + " onCreate");
-
-
// NOTE* This Activity MUST contain a ListView named "@android:id/list"
-
// (or "list" in code) in order to be customized
-
// http://code.google.com/android/reference/android/app/ListActivity.html
-
this.setContentView(R.layout.review_list);
-
-
this.empty = (TextView) findViewById(R.id.empty);
-
-
// set list properties
-
final ListView listView = getListView();
-
listView.setItemsCanFocus(false);
-
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
-
listView.setEmptyView(this.empty);
-
}
-
-
@Override
-
protected void onResume() {
-
super.onResume();
-
Log.v(Constants.LOGTAG, " " + ReviewList.CLASSTAG + " onResume");
-
// get the current review criteria from the Application (global state placed there)
-
RestaurantFinderApplication application = (RestaurantFinderApplication) getApplication();
-
String criteriaCuisine = application.getReviewCriteriaCuisine();
-
String criteriaLocation = application.getReviewCriteriaLocation();
-
-
// get start from, an int, from extras
-
int startFrom = getIntent().getIntExtra(Constants.STARTFROM_EXTRA, 1);
-
-
loadReviews(criteriaLocation, criteriaCuisine, startFrom);
-
}
-
-
@Override
-
public boolean onCreateOptionsMenu(Menu menu) {
-
super.onCreateOptionsMenu(menu);
-
menu.add(0, ReviewList.MENU_GET_NEXT_PAGE, 0, R.string.menu_get_next_page).setIcon(
-
android.R.drawable.ic_menu_more);
-
menu.add(0, ReviewList.MENU_CHANGE_CRITERIA, 0, R.string.menu_change_criteria).setIcon(
-
android.R.drawable.ic_menu_edit);
-
return true;
-
}
-
-
@Override
-
public boolean onMenuItemSelected(int featureId, MenuItem item) {
-
Intent intent = null;
-
switch (item.getItemId()) {
-
case MENU_GET_NEXT_PAGE:
-
// increment the startFrom value and call this Activity again
-
intent = new Intent(Constants.INTENT_ACTION_VIEW_LIST);
-
intent.putExtra(Constants.STARTFROM_EXTRA, getIntent().getIntExtra(Constants.STARTFROM_EXTRA, 1)
-
+ ReviewList.NUM_RESULTS_PER_PAGE);
-
startActivity(intent);
-
return true;
-
case MENU_CHANGE_CRITERIA:
-
intent = new Intent(this, ReviewCriteria.class);
-
startActivity(intent);
-
return true;
-
}
-
return super.onMenuItemSelected(featureId, item);
-
}
-
-
@Override
-
protected void onListItemClick(ListView l, View v, int position, long id) {
-
// set the current review to the Application (global state placed there)
-
RestaurantFinderApplication application = (RestaurantFinderApplication) getApplication();
-
application.setCurrentReview(this.reviews.get(position));
-
-
// startFrom page is not stored in application, for example purposes it's a simple "extra"
-
Intent intent = new Intent(Constants.INTENT_ACTION_VIEW_DETAIL);
-
intent.putExtra(Constants.STARTFROM_EXTRA, getIntent().getIntExtra(Constants.STARTFROM_EXTRA, 1));
-
startActivity(intent);
-
}
-
-
private void loadReviews(String location, String cuisine, int startFrom) {
-
-
Log.v(Constants.LOGTAG, " " + ReviewList.CLASSTAG + " loadReviews");
-
-
final ReviewFetcher rf = new ReviewFetcher(location, cuisine, "ALL", startFrom,
-
ReviewList.NUM_RESULTS_PER_PAGE);
-
-
this.progressDialog = ProgressDialog.show(this, " Working…", " Retrieving reviews", true, false);
-
-
// get reviews in a separate thread for ProgressDialog/Handler
-
// when complete send "empty" message to handler
-
new Thread() {
-
@Override
-
public void run() {
-
reviews = rf.getReviews();
-
handler.sendEmptyMessage(0);
-
}
-
}.start();
-
}
-
}
在android里,新产生一个线程并不会自动建立其Message Loop。Android里并没有Global 的Message Queue,所以不同的APK里不能透过Message Queue来交换信息
相关推荐
Looper MessageQueue 源码解析,通过源码 手写一套自己的Handler。
Handler+Looper+MessageQueue
Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理. 简单定义: 1、Message Queue(消息队列): 用来存放通过Handler发布的消息,通常...
Android 异步处理 Handler+Looper+MessageQueue深入详解
android源码中包含了...android的消息处理有三个核心类: Looper,Handler和Message。 其实还有一个Message Queue(消息队列) , 但是MQ被封装到Looper里面了, 我们不会直接与 MQ打交道, 因此我没将其作为核心类。
Message,MessageQueue,Looper,Handler详解
作用: 跨线程通信,异步通信。...MessageQueue(消息队列):由Looper负责管理,管理Handler发送过来的Message,其底层实现采用的是单链表。 Handler(处理者):负责Message的发送及处理。通过 Handler.send
handler与looper及messagequeue的简单总结
NULL 博文链接:https://null-point.iteye.com/blog/1356138
主要介绍了深入Android Handler,MessageQueue与Looper关系,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
你可以诞生Handler之对象来与Looper沟通,以便push新讯息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的讯息。 线程A的Handler对象参考可以传递给别的线程,让别的线程B或C等能送讯息来给...
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。 Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法...
安卓应用开发基础的消息处理机制分析。对应用工程师很有帮助。
Looper,MessageQueue,Handler分析之ActivityThread.java
从源码出发,详细的解析了android中的消息机制,分析清楚Looper和MessageQueue以及Handler三者之间的关系。
使用处理程序延迟主线程上的工作;...我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱中。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。
本篇文章是对Handler,Looper与MessageQueue进行了详细的分析介绍,需要的朋友参考下
android线程消息机制主要由Handler,Looper,Message和MessageQuene四个部分组成。平常在开发中,我们常用来在子线程中通知主线程来更新,其实整个安卓生命周期的驱动都是通过Handler(ActivityThread.H)来实现的。 ...
Looper 使线程保持活动状态,循环 MessageQueue 并向相应 Handler 的进程发送消息。 Thread 通过调用 Looper 的 quit() 方法终止。 Handler 及其组件 Handler:框架的重要对象,它具有双重责任。它绑定到给定线程...