Android 中的消息机制
Android 中的消息机制
我们先来看一些术语:
1.Parcel:其实就是一个容器,我们来看官方描述:Container for a message (data and object references) that can be sent through an IBinder。很简单,就是一个消息的集合,而这样的集合是可以通过IBinder接口发送的。
2.Message:Defines a message containing a description and arbitrary data object that can be sent to aHandler
. :消息就是一种包含描述和任意数据而且能够发送给Handler的数据结构。
3.Handler:A Handler allows you to send and process Message
and Runnable objects associated with a thread'sMessageQueue
. Each Handler instance is associated with a single thread and that thread's message queue.:Handler 允许你发送以及处理与某个线程的消息队列关联的消息和Runnable对象。每个Handler实例是和单个线程以及它的消息队列是关联起来的。
4.Looper:Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, callprepare()
in the thread that is to run the loop, and thenloop()
to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler
class.:一个类,什么样的类呢?用于运行某个线程的消息循环的类。通常情况下,一个线程是不含一个与自身关联的消息loop的。如果new一个thread,需要在你的线程中调用prepare()函数来启动loop,然后loop()在终止之前会自己处理消息。对于一般的主线程来说,会自动创建一个mainloop与主线程绑定。可以使用getMainLooper()来获取主线程的loop函数。
5.MessageQueue:Low-level class holding the list of messages to be dispatched by aLooper
. Messages are not added directly to a MessageQueue, but rather throughMessageQueue.IdleHandler
objects associated with the Looper.You can retrieve the MessageQueue for the current thread withLooper.myQueue()
.:也是一个类,什么样的类呢?保存了N个用于被Looper分发的Message的类。因为我们的Message不是直接add到MessageQueue里面的,而是通过一个MessageQueue.IdleHandler
的对象来和Looper关联起来的,我们可以通过Looper.myQueue()
来获取到当前线程的消息队列。
好了,上面的术语基本上都是Android消息机制相关的术语,也做了一些简单翻译,讨厌看的童鞋可以看看英文原始注释。俺们一起来理下思路:
· N个消息放一起,堆在一个容器里面,该容器里面的东东而且能够通过IBinder形式发送,这就形成了Parcel。(Parcel的用法暂时不单独提了,后面相关技术文档会涉及到了就说,这个在Android Framework里面用的比较多。)
·通常我们的Message不是发一条就处理一条的,它首先是放在消息队列里面的进行逐条处理,怎么放到消息队列里面的呢?不是直接的add进去,而是和Looper关联的一个MessageQueue.IdleHandler对象来add进去的,这里就看到了,looper起到了Message和MessageQueue的一个桥梁作用(记住:消息队列中的消息也是由Looper给整出去的。),这个还不是最主要的。looper最主要的桥梁作用是Message和Handler,Looper它可以分发消息,分发的消息是给Hander进行发送和处理的。Hanlder通过looper从MessageQueue里面获取Message进行处理。它也可以get 消息,然后add到消息队列里面去。
6.AsyncTask :这是个异步任务机制,也是来捣鼓线程间通信的,该机制将相应操作在线程池中取出一个线程来执行,然后将结果传递给主线程,主线程拿到该结果后即可以进行更新界面等相应操作了。
AsyncTask的使用需要我们去创建一个继承自AsyncTask的类AsyncTask<Params
, Progress
, Result
>,
参数说明如下:
Params
, the type of the parameters sent to the task upon execution.:发送给异步任务去执行的参数类型。Progress
, the type of the progress units published during the background computation.:在后台执行程序的时候返回给调用线程进度的参数类型。Result
, the type of the result of the background computation.:后台执行程序计算好的结果类型。
doInBackground(String... params) :后台执行程序,参数params是由调用线程传递过来。然后将返回的结果送给onPostExecute, onPostExecute可以依据放回的结果来更新UI的操作。在子线程中操作。
onCancelled():可以在处理的过程中取消异步线程处理。如果执行已经结束的话该方式执行失败。在主线程中操作。
onPostExecute(String result):从doInBackground获取执行后的结果,然后可以对UI的主界面进行更新操作。该操作的执行是在主线程中。
onPreExecute() :执行子线程前进行的一系列的准备工作。该操作在主线程中操作。
onProgressUpdate(String... values):主线程中用于显示进度的函数,该函数由doInBackground()调用publishProgress()函数将结果发送过来。在主线程中操作。
以上几个函数都是回调函数,系统会自己调用,切忌不要手动去调用它。
通常情况下我们使用AsyncTask的情况会比较多,因为它比handle机制简单,而且使用起来也比较方便,在后面的例子中将会将两种情况一起使用。
实例:
介绍,该例子主要是利用Handle的消息机制实现一个音乐播放器;用AsyncTask形式实现点击按钮就更改UI界面的文字信息。两种方式都是多线程的通信方式。具体注释贴代码如下:
HandleMessageActivity.java
- import java.security.PublicKey;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
- import android.os.Looper;
- import android.content.Intent;
- public class HandleMessageActivity extends Activity {
- /** Called when the activity is first created. */
- private Button mBtnPlayMusic = null;
- private Button mBtnStopMusic = null;
- private Button mBtnChangeWelInfo = null;
- private TextView mTextShowMusicName = null;
- private TextView mTextWelcomeInfo = null;
- Looper loop = Looper.myLooper();//获取主线程的looper
- MyHandle myHandle = new MyHandle();//new一个Handle,来处理主线程的消息信息
- private String mArgs = null;//这个用于AsyncTask中的参数传递。
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mBtnPlayMusic = (Button)findViewById(R.id.play_music);
- mBtnStopMusic = (Button)findViewById(R.id.stop_music);
- mBtnChangeWelInfo = (Button)findViewById(R.id.changeText);
- mTextShowMusicName = (TextView)findViewById(R.id.music_name);
- mTextWelcomeInfo = (TextView)findViewById(R.id.welcomeinfo);
- /**
- * 实现播放音乐的功能
- */
- mBtnPlayMusic.setOnClickListener(new Button.OnClickListener(){
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- new Thread(){
- public void run(){
- //实现细节
- System.out.println(" star music:Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("star music Current Thread Name is:"+Thread.currentThread().getName());
- //获取包内的资源:取得music的全路径名称
- String musicName = getResources().getString(R.raw.dongni);
- System.out.println("the full of music name and path is:"+musicName);// res/raw/dongni.mp3
- System.out.println("the full of resource name and path is:"+getResources().getResourceName(R.raw.dongni));//这里返回的包含了包得路径
- //获取路径,不需要后缀名
- int b = musicName.lastIndexOf("/");
- int e = musicName.lastIndexOf(".");
- String musicTrueName = musicName.substring(b+1, e);
- /**
- * 定义消息,并和Handle关联起来,这里注意的是,该消息只会和所定义的Handle关联起来,
- * 而我们这里的Handle是在UI主线程里面创建的,所以此处的消息是会发送给UI的消息队列的。
- */
- Message message = myHandle.obtainMessage();
- message.arg1 = 0;//用于区分在哪个线程里面发过来的Handle消息。
- message.obj = musicTrueName;//所发送的对象
- message.sendToTarget();//将消息发送给UI线程。
- Intent intent = new Intent(HandleMessageActivity.this,MusicServer.class);
- startService(intent);//启动service
- }
- }.start();
- }
- });
- /**
- * 实现停止音乐播放的功能
- */
- mBtnStopMusic.setOnClickListener(new Button.OnClickListener(){
- public void onClick(View v){
- new Thread() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- System.out.println("stop music Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("stop music Current Thread Name is:"+Thread.currentThread().getName());
- Message stopMsg = myHandle.obtainMessage();//获取消息对象,表示要发送给myHandle的消息
- stopMsg.arg1 = 1;//给消息赋值
- stopMsg.sendToTarget();//发给myHandle
- Intent intent = new Intent(HandleMessageActivity.this,MusicServer.class);
- stopService(intent);//停止service
- }
- }.start();
- }
- });
- /**
- * 改变欢迎信息,这里使用AsynTask的方式来执行
- */
- mBtnChangeWelInfo.setOnClickListener(new Button.OnClickListener(){
- public void onClick(View v){
- System.out.println("in mBtnChangeWelInfo ,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("in mBtnChangeWelInfo ,Current Thread Name is:"+Thread.currentThread().getName());
- mArgs = "100";
- new AsynTask().execute(mArgs);
- /*
- new Runnable() {
- @Override
- public void run() {
- System.out.println("Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("Current Thread Name is:"+Thread.currentThread().getName());
- Message changeTextMsg = myHandle.obtainMessage();
- changeTextMsg.arg1 = 20;
- changeTextMsg.obj = "改变欢迎信息";
- changeTextMsg.sendToTarget();
- }
- }.run();
- */
- }
- });
- }
- /**
- *
- * @author bluesky
- * 定义主线程的处理程序,这里我们复写handleMessage来处理发送给UI线程的消息。
- */
- class MyHandle extends Handler{
- public MyHandle(){
- }
- public MyHandle(Looper loop){
- super(loop);
- }
- @Override
- public void dispatchMessage(Message msg) {
- // TODO Auto-generated method stub
- super.dispatchMessage(msg);
- }
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- super.handleMessage(msg);
- switch(msg.arg1){
- case 0:
- CharSequence getMusicName = (CharSequence)msg.obj;
- mTextShowMusicName.setText(getMusicName);
- break;
- case 1:
- CharSequence change = "no music played";
- mTextShowMusicName.setText(change);
- break;
- // case 20:
- //mTextWelcomeInfo.setText(msg.obj.toString());
- //break;
- default:
- break;
- }
- }
- @Override
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
- // TODO Auto-generated method stub
- return super.sendMessageAtTime(msg, uptimeMillis);
- }
- @Override
- public String toString() {
- // TODO Auto-generated method stub
- return super.toString();
- }
- }
- /**
- *
- * @author bluesky
- * 异步消息处理类,用于处理异步操作。
- */
- class AsynTask extends AsyncTask<String, String, String>{
- /**
- * 后台进行一些处理操作,然后将返回的结果送给onPostExecute,
- * onPostExecute可以依据放回的结果来更新UI的操作。
- * 在线程池中操作
- */
- @Override
- protected String doInBackground(String... params) {
- // TODO Auto-generated method stub
- System.out.println("do InBackground,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("do InBackground,Current Thread Name is:"+Thread.currentThread().getName());
- String getParam = null;
- getParam = params[0];
- String progress = "测试更新进度";
- publishProgress(progress);
- return getParam;
- }
- /**
- * 可以再处理的过程中取消异步线程处理。
- */
- @Override
- protected void onCancelled() {
- // TODO Auto-generated method stub
- System.out.println("do onCancelled,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("do onCancelled,Current Thread Name is:"+Thread.currentThread().getName());
- super.onCancelled();
- }
- /**
- * 从doInBackground获取执行后的结果,然后可以对UI的主界面进行更新操作。
- * 在主线程中操作
- */
- @Override
- protected void onPostExecute(String result) {
- // TODO Auto-generated method stub
- System.out.println("do onPostExecute,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("do onPostExecute,Current Thread Name is:"+Thread.currentThread().getName());
- if(result == "100"){
- mTextWelcomeInfo.setText("AsynTask方式改变UI显示!");
- }
- }
- /**
- * 在主线程中进行一系列的准备工作。
- *
- */
- @Override
- protected void onPreExecute() {
- // TODO Auto-generated method stub
- System.out.println("do onPreExecute,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("do onPreExecute,Current Thread Name is:"+Thread.currentThread().getName());
- Toast.makeText(HandleMessageActivity.this, "开始使用AsynTask来进行进程中通信", Toast.LENGTH_LONG).show();
- super.onPreExecute();
- }
- /**
- * 主线程中用于显示进度的函数,该函数由doInBackground()调用publishProgress()函数将结果发送过来。
- */
- @Override
- protected void onProgressUpdate(String... values) {
- // TODO Auto-generated method stub
- String getProgress = values[0];
- System.out.println("do onProgressUpdate,Current Thread ID is:"+Thread.currentThread().getId());
- System.out.println("do onProgressUpdate,Current Thread Name is:"+Thread.currentThread().getName());
- System.out.println("do onProgressUpdate,Current value get from doInBackGround is:"+getProgress);
- }
- }
- }
|
评论暂时关闭