Android的一些基本常识
16lz
2021-12-20
1.Message
1.1 主要成员
public final class Message implements Parcelable{ public int what;//user-defined message code public int arg1; public int arg2; public Object obj;//arbitrary object to send to recipient /** *一个可选的Messenger对象,表示这个消息的回复要发给谁,AsynChannel类就 * 用到了这个成员 **/ public Messenger replyTo; Handler target;//处理这个消息的Handler public static Message obtain(); public static Message obtain(Message orig); public static Message obtain(Handler h) ; public static Message obtain(Handler h, int what); public static Message obtain(Handler h, int what, Object obj) ; public static Message obtain(Handler h, int what, int arg1, int arg2); public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj); public void sendToTarget();}
1.2 说明
Message类定义了消息结构体,里面包含了arg1,arg2用以携带基本的信息,这样大部分情况下可以不用分配内存。如果arg1,arg2满足不了要求,还可以使用obj和setData来传递更丰富的信息。 通常情况下,使用obtain()函数或者Handler::obtainMessage来构造Message类实例2.Hanlder
2.1Handler类的作用
Hanlder类,主要用来实现消息处理函数。 简单地说,Looper是一个循环,它有一个Message que,会不停地读Message que,读出来的message,就调用改message对应的Handler(也就是message的target成员变量)的handleMessage或者message的callback进行处理。这个Looper通常运行在一个Thread上,但是Thread缺省并不带Looper,一般调用Looper.prepare()和Looper.loop()将循环运行起来。调用Handler.::sendMessage主要做两件事,一是将该Handler的值赋给message.target,而是将message enque到Looper的Message que中。下面一个简单例子展示这种关系。class LoopThread extends Thread{ public Handler mHandler; public void run(){ Looper.prepare(); mHandler =new Handler(){ public void handleMessage(Message msg){ //process incoming message } }; Looper.loop(); }}//somewhereLoopThread thread=new LooperThead();thread.run()//somewheremHandler.sendMessage(msg)
2.2 HandlerThread
为了简化Hanlder,Loop,Thread之间的处理,Android定义了一个HanlderThread类,派生自Thread,特别的是,默认就带有一个looperClass SampleHandler extends Handler{ SampleHandler(android.os.Looper looper){ super(looper); } public void handlerMessage(Message msg){ //handler incoming mssage }}HandlerThread sampleThread = new HandlerThread("SampleService");sampleThread.start();mSampleHandler = new SampleHandler(sampleThread.getLooper());//somewheremSampleHandler.sendMessage(msg);
2.3 官方文档对Handler的说明
Handler允许你发送和处理和thread的MessageQue关联的消息和Runnable objects。每个Handler实例都同一个单独的Thread和那个Thread的MessageQue关联。当你创建了一个Handler,它就绑定到创建它的thread和thread的MessageQue上,它deliver messages和Runnables到那个MessageQue,当它们从MessageQue取出时执行他们。 There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own. schedule messages通过post,postAtTime,postDelayed,sendEmptyMessage,sendMessage,sendMessageAtTime,sendMessageDelayed等方法来完成。 其中,post系列的函数用来schedule Runnables。而sendMessage系列的函数用来enqueue message ,该message可以包含a bundle of data,传递给handleMessage。2.4 其它
Handler类还声明了一个成员变量 IMessenger mMessenger; 并提供了接口 final IMessenger getIMessenger()通过这个可以将可跨进程传递的IMessager同进程内部的Handler联系起来,Messenger类利用了这个实现了跨进程通信。
3.Messenger
3.1 介绍
Messenger类是Handler的一个索引,但是它通过Binder的一个简单封装,实现了Handler无法实现的进程间通信。public final class Messenger implements Parcelable{ private final IMessenger mTarget; /** * 创建一个指向target的Messenger,任何发给这个Messenger的 * 消息就会像Handler::sendMessage一样,被target这个Handler * 处理 * */ public Messenger(Handler target); /** * 通过一个raw IBinder来创建Messenger,比如client端连接service的时候, * 通过onServiceConnected获取到IBinder对象,就可以构建出service的 * Messenger,从而可以像service发送消息 * */ public Messenger(IBinder target); /*注意因为是跨进程通信,要catch exception*/ public void send(Message message) throws RemoteException; /** * 获取messenger用来同对应Handler通信的IBinder对象,比如service在onBind * 接口可以调用这个接口返回IBinder对象给client,也就是client在 * onServiceConnected获取到的IBinder * */ public IBinder getBinder(); }
3.2 实例
下面以一个实例展示如何利用Messenger来实现client和bound service之间的通信,可以简单分为如下几个步骤- Service实现一个Handler来处理消息
- Service利用这个Handler来创建Messenger
- Service在onBind接口中,利用Messenger::getBinder()将IBinder对象返回
- Client在ServiceConnection::onServiceConnect中接收到这个IBinder对象,利用这个IBinder对象,构建出远端Messenger
- client端利用这个远端Messenger向service发送消息(Messenger::send)
- sercie在Handler里面处理消息
public class MessengerService extends Service { /** Command to the service to display a message */ static final int MSG_SAY_HELLO = 1; /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * When binding to the service, we return an interface to our messenger * for sending messages to the service. */ @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }}
public class ActivityMessenger extends Activity { /** Messenger for communicating with the service. */ Messenger mService = null; /** Flag indicating whether we have called bind on the service. */ boolean mBound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the object we can use to // interact with the service. We are communicating with the // service using a Messenger, so here we get a client-side // representation of that from the raw IBinder object. mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; // Create and send a message to the service, using a supported 'what' value Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // Bind to the service bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } }}
几点讨论
- 这种方式client只能向service发送消息,不能像LocalBinder或者AIDL那样通过client直接调用远端service的method
- 因为MessageQue是串行处理的,这种方式一次只能处理一个请求,不像aidl可以同时处理多个请求,相应地也没有multi-thread的问题
- 上个例子中,这种通信是单向的,只能client向service发送消息,如果想service也可以主动向client发消息,可以设置message的replyTo,也可以使用AsyncChannel。其实AsyncChannel就是利用利用两个Messenger来实现双工通信。
- 因为是Remote Process Call,所以Messenger::send调用要注意catch exception
3.3 补充
Messenger这种进程间通信的本质就是获得另一端Handler对应的Messenger,所以除了在Service::onBind中返回IBinder对象外,只要能获取Messenger对象就可以,比如结合AIDL,可以利用AIDL的函数调用来获得远端的Messenger.4.AIDL
4.1 什么是AIDL
AIDL(Android Interface Definition Language)用来帮助实现跨进程通信。仅在需要从不同的应用通过IPC同时访问service(需要处理multi-thread)的情况下使用AIDL通信,如果不需要跨进程,可以使用LocalBinder,如果不需要同时处理请求(多线程),可以使用messenger。AIDL通常用于实现Bounding Service。4.2 AIDL的实现
4.2.1 Service端
- 创建.aidl文件xxx.aidl
- 实现aidl文件中的interface
Android SDK工具会根据第一步的.aidl,自动生成xxx.java,在这个xxx里面有个.Stub抽象类,这个.Stub抽象类派生自Binder,负责实现aidl中的接口。所以你要做的工作就是继承这个抽象类,实现它。
那个自动生成的抽象类.stub
public static abstract class Stub extends Binder implements DataService; - 将interface expose给client
在Service::onBind中返回你实现的.stub类的实例
Interface DataService{ double getData(String arg);}
实现接口并expose给client
public class AIDLExampleService extends Service{ private final DataService.Stub mBinder = new DataService.Stub(){ public double getData(String arg) { /*implement your operation,it should be thread safe*/ return 0; } } /*expose the interface*/ public IBinder onBind(Intent intent){ return mBinder; }}
4.2.2 Client端
- include .aidl文件到src目录
- 声明一个IBinder接口实例
- 实现ServiceConnection
- 调用context.bindService,传入ServiceConnection实现
- 在ServiceConnection::onServiceConnected()接口中接收IBinder实例,调用xxx.Stub.asInterface()接口进行类型转换
- 利用IBinder接口实例来调用远端方法,注意catch RemoteException
- 调用unbindService disconnect
public class AIDLExampleActivity extends Activity{ private Button button;//按钮触发调用 private DataService mService=null; private boolean mBound; private ServiceConnection = new ServiceConnection(){ public void onServiceDisconnected(ComponentName name){ mService=null; mBound=false; } public void onServiceConnected(ComponentName name,IBinder service){ mBound=true; mService=DataService.stub.asInterface(service); } } protected void onCreate(Bundle savedInstanceState){ //onCreate的一些normal implementation //bind service Intent intent=new Intent("***.DataService"); bindService(intent,connection,BIND_AUTO_CREATE); button.setOnClickListener(new View.onClickListener(){ public void onClick(View v){ if(mBound && mService!=null){ double result=mService.getData("a"); /**desplay in ui***/ } } }); } }
4.3 其他
4.3.1 关于AIDL interface在哪个线程执行
- 如果是本地Process发起的调用,就在发起调用的那个线程执行
- 如果是从其它Process发起的调用,会从本进程的线程池中选一个线程执行。也就是说,同时可能产生多个调用,因此AIDL interface的实现必须保证线程安全
4.3.2 通过IPC传递Objects
- 让你要传递的类实现Parcelable接口(实现writeToParcel和CREATOR)
- 创建一个aidl文件,声明这个Parcellable class
更多相关文章
- android 调用本地音乐播放器
- Android:使用SpannableString实现图片替换相应的文字
- 多个Android(安卓)device offline处理命令
- Android弹出对话框简单代码
- android 图文列表的实现方法
- android 实现保存图片到相册
- Android调用安卓相机拍照上传
- 【Android】上周问题记录
- 浅谈Java中Collections.sort对List排序的两种方法