Android Service绑定与跨进程通信
来源:互联网 发布:淘宝上好吃的零食推荐 编辑:程序博客网 时间:2024/05/01 06:37
为什么要绑定Service?
Android的在服务器-客户端模式大量使用了Service绑定。绑定Service的好处就是你可以向Service发送、接收请求,甚至可以跨进程通信(IPC)。被绑定的服务通常是为了其他进程服务,而不是正常情况下的后台处理事件。
绑定Service的办法
在客户端中使用bindService (Intent service, ServiceConnection conn, int flags)
。
其中几个参数分别意义为:
Intent
: 指向绑定Service的Intent。若是在其他进程中的Service,需要调用Intent.setComponent(new ComponentName(String packageName, String className))
来指定Service。
ServiceConnection
:提供绑定连接的接口,有两个方法必须实现:
onServiceConnected(ComponentName name, IBinder service)
在连接建立时被调用的函数,参数意义如下:
name 被绑定服务的具体名,格式:”ComponentInfo{app_package/service_package.service_class}”。
service 服务的
onBind
方法所返回的IBinder
,可以用来与服务通信。
onServiceDisconnected(ComponentName name)
在连接断开时被调用的函数,参数name与
onServiceConnected
中含义相同。
flags
: Context类下的常量,具体意义如下表
onStartCommand
仍然未被调用(它只会在显式调用startService
时才会被调用)。 BIND_DEBUG_UNBIND 2 使用此标志绑定服务之后的unBindService
方法会无效。 这种方法会引起内存泄露,只能在调试时使用。 BIND_IMPORTANT 64 被绑定的服务进程优先级会被提到FOREGROUND级别 BIND_NOT_FOREGROUND 4 被绑定的服务进程优先级不允许被提到FOREGROUND级别 BIND_WAIVE_PRIORITY 32 被绑定的服务进程不会被OOM列入猎杀对象中。关于进程优先级,系统在将要发生Out Of Memory(OOM)异常时会挑优先级最高的进程先杀死来释放内存,具体见参考文献Android Process。
要和所绑定的Service交互,都是通过实现ServiceConnection
接口,在其中的onServiceConnected
方法中获取到IBinder
示例,并通过以下几种方法进行沟通。
1. 继承Binder
如果服务器提供的Service与客户端在一个进程内(说白了就是访问自己进程内的另一个Service), 用这种方法访问Service是你最好的选择。
你可以通过在Service中实现一个公共内部类继承Binder
,并在Service的onBind()
方法中返回这个内部类的一个实例。
在客户端中可以直接将获取到的IBinder
类型转换为Service中定义的公共内部类,并通过它来与Service通信。
具体实现方法
本地服务类的实现:
public class LocalService extends Service { public static final String TAG = "LocalService"; // 要传递给客户端的Binder实例。 private final IBinder mBinder = new LocalBinder(); private final Random mGenerator = new Random(); /** * 继承Binder的类,必须为public。 * 通过getService()获取Service实例。 */ public class LocalBinder extends Binder { LocalService getService() { return LocalService.this; } } /** 当被绑定时传回Binder实例 */ @Override public IBinder onBind(Intent intent) { return mBinder; } /** 测试用的函数 */ public void showLog(String message) { Log.i(TAG, message); }}
本地客户端绑定:
public class BindingActivity extends Activity { LocalService mService; boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override protected void onStart() { super.onStart(); // 绑定Service Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); mService.showLog("call from client."); } @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; } } /** 实现ServiceConnection */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // 将IBinder转换为LocalBinder LocalService.LocalBinder binder = (LocalService.LocalBinder) service; mService = binder.getService(); mBound = true; } @Override public void onServiceDisconnected(ComponentName arg0) { mBound = false; } };}
2. 使用Messenger
如果客户端访问的Service在其他进程中,你可以通过Messenger
来提供/获取服务接口。 Service
可以实现一个Handler
来处理不同的消息,Messenger
可以通过IBinder将Handler传递给客户端,从而实现消息传递。同时客户端也可以使用Messenger
让服务端传消息过来。
这是最简单的跨进程交流的办法,因为Messenger
将消息队列保持在一个线程之内,服务端同一时间只能处理一个请求,你不需要考虑复杂的线程同步问题。
具体实现:
服务进程实现:
public class MessengerService extends Service { public static final String TAG = "MessengerService"; static final int MSG_SAY_HELLO = 1; /** * 用来处理消息的Handler */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_SAY_HELLO: Log.i(TAG, "hello from client process."); break; default: super.handleMessage(msg); } } } /** * 将Handler实例传给Messenger */ final Messenger mMessenger = new Messenger(new IncomingHandler()); /** * 当被绑定时传回包含Messenger的IBinder。 */ @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }}
客户进程实现:
public class ActivityMessenger extends Activity { static final int MSG_SAY_HELLO = 1; Messenger mService = null; boolean mBound = false; /** * 实现ServiceConnection */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { /* 当绑定建立时获取服务端的Messenger */ mService = new Messenger(service); mBound = true; } public void onServiceDisconnected(ComponentName className) { /* 当连接断开后释放Messenger,防止内存泄露 */ mService = null; mBound = false; } }; public void sayHello(View v) { if (!mBound) return; Message msg = Message.obtain(null, 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(); bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onStop() { super.onStop(); if (mBound) { unbindService(mConnection); mBound = false; } }}
3. 使用AIDL
AIDL将消息压缩成原始数据流然后在进程之间传递,Messenger
的实现就是基于AIDL。 仅仅当你的Service需要同时处理多个请求时你才需要自己实现AIDL,否则你应该使用Messenger
实现跨进程交流。
如果要实现AIDL,你要创建一个.aidl
文件,Android ADK tool会自动创建一个虚类来提供处理IPC消息的接口,你可以通过实现接口来处理消息。
再一次提示:大部分应用并不适合直接实现AIDL,只有当Service必须同时处理多个请求时,你才直接实现它。
鉴于AIDL并不推荐自己实现,而且实现起来较为复杂,本文暂不提供实现办法。有兴趣的同学可以参考以下两个网站,他们都提供了比较具体的实现办法:
AIDL进程间传递自定义类型参数
Android Interface Definition Language (AIDL) (需翻墙)
被绑定Service的生命周期
如果Service只是由bindService
启动的,那么无须关注它的生命周期,当所有对Service的绑定断开之后,系统会自动杀死Service。
但是当Service是由startService
启动的,则情况就不一样了。这种情况下Service的onStartCommand
会被执行,必须显式地调用stopService
,service才会被杀死。这种情况下你可以让Service判断是否有客户端在解除绑定后重新绑定,并实现onRebind
进行相应操作(可以返回与onBind
不一样的IBinder
)。通过重写Service的onUnBind
函数返回true来告诉Service是否要使用onRebind
。
下图来自Android API Guides - Bound Service,清晰地阐述了被绑定Service的生命周期:
几点提示
由于服务进程是有可能在中途被杀死的,在客户端保持
mBound
布尔值来判断是否连接仍然健康是必要的,否则你应该监控是否有DeadObjectException
的发生。绑定Service后一定要在onStop或者onDestroy中调用
unBindService
释放连接,否则会有内存泄露。 具体要和哪个生命周期进行搭配,取决于应用需要,参考Managing the Activity Lifecycle.无论Service被多少个线程绑定,它都只会返回同一个IBinder实例。
参考文献
Android API Guides - Bound Service
Android API Guides - AIDL
IBinder
Android Process
Handler
- Android Service绑定与跨进程通信
- android Service 跨进程通信
- android Service 跨进程通信
- android Service 本地通信与跨进程通信
- Android中Service与跨进程的Activity通信。
- 跨进程绑定Service
- Android的服务(Service)(三)Service客户端的绑定与跨进程
- Android的服务(Service)(三)Service客户端的绑定与跨进程
- Android的服务(Service)(三)Service客户端的绑定与跨进程
- android service 与activity通信--绑定service
- Android:Service的绑定和解绑定,Service与Activity通信
- Service的绑定中,Binder跨进程与非跨进程的区别
- Activity与Service跨进程通信(Messenger方式)
- Android bind service讲解以及跨进程通信
- android 跨进程通信
- Android 跨进程通信
- Android跨进程通信
- Android跨进程通信
- 大数据时代:内存数据网格逐步成为主流
- 初识分布式服务管理框架-Dubbo
- 使用Apache Solr对数据库建立索引(包括处理CLOB、CLOB)
- 侧滑删除进阶(二)
- 彩色TabBar切换动画实现
- Android Service绑定与跨进程通信
- .NET平台和C#编程基础知识复习
- HDU1162
- 大家对华为的评价
- MQ JMS发送消息并接收客户端回复
- PAT 1025. PAT Ranking (25)
- VB.NET线程池应用实例
- 第一课python
- mybatis实现数据的批量删除