android bindService()
bindService简介
Service一般用于不用显示,运行在后台的服务。
startService 是我们最常用的启动Service的方法。而如何让service与其他组件通信呢?一般在一个进程内,可以使用广播的方式让Service与本进程其他Actvity/service进行通信,那么还有更好的方法吗?如果要进行进程间通信(IPC)呢?
bindService就是解决这些问题的。
Binder通信机制介绍
在学习bindService之前,有必要对Binder通信机制有个基本的认识。为了提供系统全局服务,让系统中的任何应用程序都能访问这个全局服务,android设计了这个叫做Binder的client/server的通信结构。
binder通信是一种client-server的通信结构,
1.从表面上来看,是client通过获得一个server的代理接口(Binder),对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。
对于开发者而言,Binder通信中有个问题需要解决:客户端如何获得服务端的Binder对象应用
Service类已经解决了这个问题
bindService和Binder机制
public boolean bindService(Intent service , ServiceConnection conn, int flags);
public interface ServiceConnection {
public void onServiceConnected(ComponetName name , IBinder service);
public void onServiceDisconnected(ComponentName name);
}
当客户端请求Ams启动某个Service后,该Service如果正常启动,那么Ams就会远程调用ActivityThread类中的ApplicationThread对象,调用的参数包含Service的Binder引用,然后在ApplicationThread中会回调bindService中的conn接口。这样客户端就可以在onServiceConnected()方法中将其参数Service保存为一个全局变量。
这样,客户端(一般是activity)就可以直接访问Service中的public方法和属性了。
BindService Basics
如果要使用BindService,Service必须要实现onBind()回调方法,onBind()返回IBinder对象,这个IBinder对象就是客户端程序中onServiceConnected()方法所需要的参数IBinder。一个客户端可以使用BinderService绑定到一个Service上,此时这个客户端必须提供ServiceConnection的实现,这样才能获得从Service中返回的IBinder。
多个客户端可以绑定到一个Service,但Service只在第一个客户端BindService时才会调用onBind()。后续BindService的客户端获得的IBinder都是从Service第一次调用onBind()中返回的IBinder。
如果Service是bindService启动的(不是startService),那么当最后一个客户端unBindService(),Service将会destroy。
Android官方定义IBinder的几种方式
扩展binder类-Extending the Binder class
如果Service不需要在多个进程间工作,那么你可以实现你自己的Binder类,让客户端(一般是Activity)可以直接调用Service的public方法。(注:在同一个应用程序中,Activity和Service都属于UI线程)
- 注解:这个方法只有在客户端和Service在同一个应用程序和线程中时才可行,这种情况很常见。例如,这个方法对于一个音乐应用程序将会非常有用,它需要绑定一个Activity到它自己的Service用来以后台播放音乐。
以下为如何设定这个binder类:
1.在你的Service中,创建一个Binder类的实例,实现以下功能之一:
-
- 包含客户端可以调用的public方法
- 返回当前Service的实例,其包含了客户端可以访问的public方法
- 或返回这个Service包含的另一个类,并含有客户端可以访问的public方法
3.在客户端,从onServiceConnected()回调方法接收这个Binder,调用bindService()。
- 注解:Service和客户端必须在同一个应用程序中的原因是客户端可以计算返回的对象并恰当的调用其APIs。服务和客户端也必须在同一个线程的原因是这种技术不能执行线程间操作。
例如,以下为一个为客户端提供了通过Binder实现接入服务中方法的服务范例:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random(); /**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
} @Override
public IBinder onBind(Intent intent) {
return mBinder;
} /** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBinder为客户端提供了getService()方法来取得当前的LocalService实例。这个允许客户端调用服务中的公共方法。例如,客户端可以从服务中调用getRandomNumber()。
以下为,当一个按钮被点击时,一个绑定到LocalService的活动并调用getRandomNumber()方法:
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();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
} @Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
} /** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
} /** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() { @Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
} @Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
使用一个消息传递器-Using a Messenger
如果你需要你的Service能够与远程进程通信,那么你可以使用一个Messenger为你的服务提供接口。这个方法允许你执行进程间通信(IPC)而不需要使用AIDL(当Service要处理多线程的客户端请求时,AIDL更加适合)。
以下为怎么样使用Messenger的总结:
- Service实现了一个Handler,用来接收每一次客户端发来的请求,并根据请求内容做处理。
- Service通过它的Handler接收每一个Message——更确切的说,是在handleMessage()方法中接收。
通过这种方法,在Service没有客户端能调用的“方法”。而是,客户传递“消息”(Message对象),同时服务在其Handler中接收。
以下为服务使用一个Messenger接口的简单范例:
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) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
注意Handler中的handleMessage()方法,Service接收客户端发来的Message,基于what成员,决定下一步的处理。
客户端所需做的只是基于Service返回的IBinder创建一个Messenger并使用send()方法发送一条消息。例如,以下为一个简单的Activity范例,其绑定到了Service,并向服务传递了MSG_SAY_HELLO消息:
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;
}
}
}
参考文章:
Android Service的绑定 基础概念篇 http://www.cnblogs.com/mengdd/archive/2013/03/24/2979710.html
android bindService()的更多相关文章
- Android bindservice使用
package com.example.myact10; import com.example.myact10.MyService.MyBinder; import android.support.v ...
- Android BindService中遇到的一个小问题
今天在使用BindService的时候遇到个小问题,我希望通过Bindservice获取到这个服务,然后执行服务内的某个自定义方法,如下: if(bindService==null){ Intent ...
- Android service ( 一 ) 三种开启服务方法
一. Service简介 Service是android 系统中的四大组件之一(Activity.Service.BroadcastReceiver.ContentProvider),它跟 Activ ...
- 新建android系统服务
一.Android系统服务 Android提供了很多系统服务:如ActivityManger,PowerManger,WindowManger,WifiManger等等. 这些服务都是系统启动开始就一 ...
- 深入理解Android的startservice和bindservice
一.首先,让我们确认下什么是service? service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互.它必须由用户或者其他程序显式的启动.它的优先级比 ...
- 【Android 界面效果34】Android里Service的bindService()和startService()混合使用深入分析
.先讲讲怎么使用bindService()绑定服务 应用组件(客户端)可以调用bindService()绑定到一个service.Android系统之后调用service的onBind()方法,它返回 ...
- Android开发之bindService()侦听service内部状态
在Android开发之bindService()通信的基础上,实现bindService()方法侦听service内部状态. 实现侦听service内部状态,使用的是回调机制 1.首先实现一个接口 p ...
- 理解Android的startservice和bindservice(转)
一.首先,让我们确认下什么是service? service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互.它必须由用户或者其他程序显式的启动.它的优先级比较高,它比处于前 ...
- 【转】Android中BindService方式使用的理解
原文网址:http://www.cnblogs.com/onlylittlegod/archive/2011/05/15/2046652.html 最近学习了一下Android里面的Service的应 ...
随机推荐
- java 获取页面中的 a 标签 的 href 实例
Pattern p = Pattern.compile("<a\\s+href\\s*=\\s*(\"|\')?(.*?)[\"|\'|>]", P ...
- 【行为型】Memento模式
备忘录模式顾名思义就是一种能有备忘作用的设计模式,其目的是在对象外部保存其在某一时刻的状态信息,并且在任何需要的时候,都可以通过备忘录中保存的状态数据恢复对象在当时情形下的状态. 备忘录模式旨在对象的 ...
- 转:前端集锦:十款精心挑选的在线 CSS3 代码生成工具
今天这篇文章向大家推荐十款非常有用的在线 CSS3 代码生成工具,这些工具能够帮助你方便的生成 CSS3 特效.CSS3 是对 CSS 规范的改善和增强,增加了圆角.旋转.阴影.渐变和动画等众多强大的 ...
- Extjs4 中在指定光标处插入值
var rulearea = Ext.getCmp(文本域Id); var rulevalue = rulearea.getValue();// 获取文本textarea 里面的值 var start ...
- ebtablesBridge
ebtables和iptables类似,都是Linux系统下网络数据包过滤的配置工具.既然称之为配置工具,就是说过滤功能是由内核底层提供支持的,这两个工具只是负责制定过滤的rules. ebtable ...
- Iterator荟萃
package com.starain.Iterator;/*代码整理快捷键为Ctrl+Shift+F * main方法输入快捷键main字符+Alt+/ * 输出快捷键sysout字符+Alt+/* ...
- linux下ssh使用和配置
常用格式:ssh [-l login_name] [-p port] [user@]hostname 更详细的可以用ssh -h查看. 举例 不指定用户: ssh 192.168.0.11 指定用户: ...
- LSPCI具体解释分析
一.PCI简单介绍 PCI是一种外设总线规范.我们先来看一下什么是总线:总线是一种传输信号的路径或信道.典型情况是,总线是连接于一个或多个导体的电气连线,总 线上连接的全部设备可在同一时间收到 ...
- jQuery 對table的基本操作
一.鼠标移动到行更换背景色: css样式: .hover{ background-color: #cccc00; } Js脚本: $(document).ready(function () { //鼠 ...
- mysql 变量set
在游标循环中,使用使用select into 变量var时,再判断var isnull 或者length(var)=0时,跳出循环. 解决方式: 使用set var=(select id from t ...