AndroidService 深度分析(2)

上一篇文章我们Service的生命周期进行了測试及总结。

这篇文章我们介绍下绑定执行的Service的实现。

绑定执行的Service可能是仅为本应用提供服务,称为本地Service。也可能为其它应用提供跨进程服务,即远程Service。以下分别进行介绍:

本地Service

假设Service仅仅服务于本应用。那么我们仅仅须要继承Binder类,定义我们须要实现的方法就可以,当发起绑定连接时,Service将会在onBind方法中返回这个继承类的对象。使得client与Service共享一个Binder对象。Binder就像一座桥梁,使client与Service可以互相联系。以下贴出本地Service的实现演示样例:

LocalService代码:

public classLocalService extends Service {
private String TAG =getClass().getSimpleName();
MyBinder myBinder = new MyBinder();
ServiceListener myServiceListener;
public LocalService() {
} public interface ServiceListener {
public String getActivityInfo();
} private void setListener(ServiceListenermyServiceListener) {
this.myServiceListener = myServiceListener;
} //绑定成功后。Service就能够通过这种方法获得Activity的信息
private void getActivityInfo() {
String activityInfo =myServiceListener.getActivityInfo();
Log.d(TAG, TAG +"+activityInfo------>" + activityInfo);
} private String getInfo() {
return "Hello,我是LocalService的方法,你能够通过它的对象訪问我。";
} public class MyBinder extends Binder {
public String getServiceInfo() {
return getInfo();
} public void setServiceListener(ServiceListenermyServiceListener) {
setListener(myServiceListener);
}
} @Override
public IBinder onBind(Intent intent) {
Log.d(TAG, TAG +"------>onBind()");
return myBinder;
} @Override
public void onRebind(Intent intent) {
Log.d(TAG, TAG +"------>onRebind()");
super.onRebind(intent);
} @Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, TAG +"------>onUnbind()");
//return false;这里的返回值决定下一次绑定时是否运行onRebind
return true;
}
}

LocalActivity代码:

public classLocalActivity extends ActionBarActivity {
private String TAG =getClass().getSimpleName();
Intent serviceIntent; @Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_local);
Log.d(TAG, TAG +"------>onCreate()");
serviceIntent = new Intent(this,LocalService.class);
} public void bindService(View v) {
Log.d(TAG, TAG +"------>bindService()");
bindService(serviceIntent,serviceConnection, Service.BIND_AUTO_CREATE);
} public void unBindService(View v) {
Log.d(TAG, TAG +"------>unBindService()");
unbindService(serviceConnection);
} @Override
protected void onDestroy() {
Log.d(TAG, TAG +"------>onDestroy()");
super.onDestroy();
} ServiceConnection serviceConnection = newServiceConnection() {
@Override
public voidonServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, TAG +"------>onServiceConnected()");
LocalService.MyBinder binder =(LocalService.MyBinder) service;
String localServiceInfo =binder.getServiceInfo();
Log.d(TAG, TAG +"+onServiceConnected------>" + localServiceInfo);
binder.setServiceListener(newLocalService.ServiceListener() {
@Override
public String getActivityInfo(){
return "Hello,我在LocalActivity中。LocalService能够调用我获得LocalActivity的消息!";
}
});
} @Override
public voidonServiceDisconnected(ComponentName name) {
Log.d(TAG, TAG +"------>onServiceDisconnected()");
}
};
}

Activity相应的布局就是两个button。分别实现绑定和解绑功能,如图:

Activity与Service都是须要在Manifest文件里注冊的哦。

我们启动Activity。先后绑定Service,输出日志例如以下:

03-17 10:10:58.525  D/LocalActivity﹕LocalActivity------>onCreate()
03-17 10:11:00.955 D/LocalActivity﹕LocalActivity------>bindService()
03-17 10:11:00.975 D/LocalService﹕LocalService------>onBind()
03-17 10:11:00.995 D/LocalActivity﹕LocalActivity------>onServiceConnected()
03-17 10:11:00.995 D/LocalActivity﹕ LocalActivity+onServiceConnected------>Hello,我是LocalService的方法。你能够通过它的对象訪问我。
03-17 10:11:16.345 D/LocalActivity﹕LocalActivity------>unBindService()
03-17 10:11:16.345 D/LocalService﹕LocalService------>onUnbind()

上面的日志显示,我们的确实现了Service的绑定与解绑工作,不仅如此,细心的你应该还发现了我们实现了Service与Activity中相互的调用吧。是的。在实际工作中我们不仅须要指示Service为我们提供服务。Service有时也须要获取到client的数据来更好地提供服务(LocalService中的getActivityInfo方法  通过回调实现)。

这里我总结下详细的实现过程:

1、在Service类中,设计继承Binder类的内部类MyBinder,加入须要向Activity提供的方法。本例中的getServiceInfo方法实现了获取Service信息的功能,当然有时候为了简便。我们直接提供方法返回Service对象。可是一般并不建议这样做;同一时候注意到setServiceListener方法。它是实现Service调用Activity提供方法的重要环节。我们通过回调的方法实现了Service对Activity的訪问。

2、重写onBind方法,并返回MyBinder对象。至此。Service类的设计就完毕了;

3、在Activity中。重写ServiceConnection接口的onServiceConnected与onServiceDisConnected方法。在onServiceConnected方法中。我们获得了onBinder方法返回的MyBinder对象。然后调用setServiceListener方法设置Service訪问Activity所须要的回掉接口对象;

4、至此,Service与Activity之间的 “桥梁”搭建完成。在Service中我们能够通过getActivityInfo方法获得Activity的信息;而在Activity中,我们也能够通过getServiceInfo方法获得Service的信息。

远程Service

当我们的Service须要为其它应用提供服务的时候,我们就要用到远程Service了。远程Service有两种实现方式,各自是Messenger方式与AIDL(Andriod进程间接口描写叙述语言)方式。以下分别进行介绍。

Messenger方式

在这样的方式中。我们定义一个Handler来处理不同的Message对象。

这个Handler是Messenger实现与client共享IBinder的基础,它同意client通过Message对象向Service发送命令。

另外,client也能够定义一个Messenger。这样,Service也能够把消息发送给client。  这是实现进程间通信的最简单的方式,由于Messenger队列将会在单线程中运行。我们不须要去考虑线程安全。

使用Messenger实现进程间通信的步骤:

l  实现一个Handler,它用来处理传递的Message对象;

l  创建一个Messenger对象,将Handler对象作为构造參数。

l  使用Messenger对象创建一个IBinder对象,并通过onBind返回;

l  client将接收到的IBinder对象作为Messenger的构造參数。实例化一个Messenger对象。这个Messenger对象将拥有Handler的引用;

l  在client通过Handler发送Message对象。Service中就能够通过Handler的handleMessage处理这个Message。

以下提供一个演示样例:

我们在ServiceTestproject下新建MessengerService类:

public class MessengerService extendsService {
/**
* Command to the service to display a message
*/
static final int MSG_SAY_HELLO = 1;
static final int MSG_GET_CLIENT_MESSENGER = 2;
static final int MSG_FROM_SERVICE = 3; private String TAG = getClass().getSimpleName();
Messenger messengerToClient; /**
* Handler of incoming messages from clients.
*/
class ServiceIncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, TAG + "------>handleMessage()");
switch (msg.what) {
case MSG_SAY_HELLO:
Log.d(TAG,"handleMessage------>MSG_SAY_HELLO!");
Toast.makeText(getApplicationContext(), "hello!",Toast.LENGTH_SHORT).show();
break;
case MSG_GET_CLIENT_MESSENGER:
Log.d(TAG,"handleMessage------>Service收到Activity的messenger对象!");
//此处获得可向client发送消息的Messenger对象
messengerToClient =msg.replyTo;
Message serviceMsg =Message.obtain(null, MSG_FROM_SERVICE, 0, 0);
try {//向client发送消息
messengerToClient.send(serviceMsg);
} catch (RemoteException e){
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
} /**
* 将这个serviceMessenger发送给client。client就能够通过它联系Service了
*/
final Messenger serviceMessenger = new Messenger(newServiceIncomingHandler()); /**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, TAG + "------>onBind()");
Toast.makeText(getApplicationContext(), "binding",Toast.LENGTH_SHORT).show();
return serviceMessenger.getBinder();
}
}

新建MessengerTestproject,并创建ActivityMessenger类:

public classActivityMessenger extends Activity {
/**
* Messenger for communicating with theservice.
*/
Messenger messengerToService = null;
/**
* Flag indicating whether we have calledbind on the service.
*/
boolean mBound;
private String TAG =getClass().getSimpleName();
/**
* Command to the service to display amessage
*/
static final int MSG_SAY_HELLO = 1;
static final intMSG_SEND_MESSENGER_TO_SERVICE = 2;
static final int MSG_FROM_SERVICE = 3; /**
* Class for interacting with the maininterface of the service.
*/
private ServiceConnection mConnection = newServiceConnection() {
public voidonServiceConnected(ComponentName className, IBinder service) {
// This is called when theconnection with the service has been
// established, giving us theobject we can use to
// interact with the service. We are communicating with the
// service using a Messenger, sohere we get a client-side
// representation of that from theraw IBinder object.
Log.d(TAG, TAG +"------>onServiceConnected()");
messengerToService = newMessenger(service);
mBound = true;
Message msg = Message.obtain(null,MSG_SEND_MESSENGER_TO_SERVICE, 0, 0);
msg.replyTo = activityMessenger;
try {//Messenger对象发送消息。这个msg对象将交给Service类中的handleMessage处理
messengerToService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
} public voidonServiceDisconnected(ComponentName className) {
// This is called when theconnection with the service has been
// unexpectedly disconnected --that is, its process crashed.
Log.d(TAG, TAG +"------>onServiceDisconnected()");
messengerToService = null;
mBound = false;
}
}; /**
* Handler of incoming messages fromservice.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg){
Log.d(TAG, TAG + "------>handleMessage()");
switch (msg.what) {
case MSG_FROM_SERVICE:
Log.d(TAG, TAG +"+MSG_FROM_SERVICE------>Activity收到Service回复的消息!");
Toast.makeText(getApplicationContext(), "MSG_FROM_SERVICE!",Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
} /**
* Target we publish for service to sendmessages to IncomingHandler.
*/
final Messenger activityMessenger = newMessenger(new IncomingHandler()); public void sayHello(View v) {
Log.d(TAG, TAG +"------>sayHello()");
if (!mBound) return;
// Create and send a message to theservice, using a supported 'what' value
Message msg = Message.obtain(null,MSG_SAY_HELLO, 0, 0);
try {//Messenger对象发送消息,这个msg对象将交给Service类中的handleMessage处理
messengerToService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
} @Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, TAG +"------>onCreate()");
} @Override
protected void onStart() {
Log.d(TAG, TAG +"------>onStart()");
super.onStart();
// Bind to the service
bindService(newIntent("com.example.servicestudy.remoteservie.MessengerService"),mConnection,
Context.BIND_AUTO_CREATE);
} @Override
protected void onStop() {
Log.d(TAG, TAG +"------>onStop()");
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}

Acitivty与Service都须要在Manifest文件里注冊。Service须要设置android:exported属性为true,并设置intent-filter。

例如以下所看到的:

<service    android:name=".remoteservie.MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<actionandroid:name="com.example.servicestudy.remoteservie.MessengerService"/>
</intent-filter>
</service>

好了,编码工作我们已经完毕了,以下我们进行一下測试。打印日志例如以下:

03-1713:11:46.195  D/ActivityMessenger﹕ActivityMessenger------>onCreate()
03-1713:11:46.195 D/ActivityMessenger﹕ActivityMessenger------>onStart()
03-1713:11:46.215 D/MessengerService﹕MessengerService------>onBind()
03-17 13:11:46.235 D/ActivityMessenger﹕ActivityMessenger------>onServiceConnected()
03-1713:11:46.275 D/MessengerService﹕MessengerService------>handleMessage()
03-17 13:11:46.275 D/MessengerService﹕ handleMessage------>Service收到Activity的messenger对象!
03-17 13:11:46.285 D/ActivityMessenger﹕ActivityMessenger------>handleMessage()
03-17 13:11:46.285 D/ActivityMessenger﹕ ActivityMessenger+MSG_FROM_SERVICE------>Activity收到Service回复的消息!
03-1713:11:55.425 D/ActivityMessenger﹕ ActivityMessenger------>sayHello()
03-1713:11:55.425 D/MessengerService﹕MessengerService------>handleMessage()
03-1713:11:55.425 D/MessengerService﹕handleMessage------>MSG_SAY_HELLO!
03-1713:12:00.665 D/ActivityMessenger﹕ActivityMessenger------>onStop()

看见了吗?完美实现了Activity与Service互相发送消息。它们都是基于Messenger对象,Activity从Ibinder处获得一个可向Service发送消息的Messenger对象,接着Activity给Service发送了一个消息,并将可向Activity发送消息的Messenger对象携带过去。这样就实现了他们之间的交互。

逻辑上和便立即都非常easy易懂吧。点个赞。

好了,既然Messenger这么简单易用,为什么我们还须要继续看AIDL方式呢?不知道你有没有想过。Messenger方式在处理client发送的消息时,是将全部消息排成一个队列,然后依次处理。也就是单线程处理方式,这样的处理方式的长处是简便不easy引起其它问题,比方线程安全。可是。对于一些即时性要求比較高的服务,这样的方式可能就不够用了,或许我们须要採用多线程的方式,将接收到的请求尽快处理。这时候就能够直接使用AIDL方式了。

AIDL方式

事实上我悄悄告诉你,Messenger方式的底层实现也是基于AIDL方式实现的,系统为了方便跨进程的服务。为我们提供了一个Messenger类来便利的实现,可是它可能无法满足我们的需求,这时候我们就须要直接基于AIDL方式实现了。

事实上AIDL的实现不难,仅仅是有非常多细节须要注意。我这里也只是多描写叙述推荐一篇文章。有代码和总结:http://blog.csdn.net/songjinshi/article/details/22918405

我把总结摘抄过来:

AIDL的创建方法: 

AIDL语法非常easy,能够用来声明一个带一个或多个方法的接口,也能够传递參数和返回值。因为远程调用的须要,
这些參数和返回值并非不论什么类型.以下是些AIDL支持的数据类型: 

1. 不须要import声明的简单Java编程语言类型(int,boolean等) 

2.String, CharSequence不须要特殊声明 

3.List, Map和Parcelables类型,
这些类型内所包括的数据成员也仅仅能是简单数据类型, String等其它比支持的类型. ( (另外:
我没尝试Parcelables,
在Eclipse+ADT下编译只是,
也许以后会有所支持). 

以下是AIDL语法: 

// 文件名称: SomeClass.aidl //
文件能够有凝视,
跟java的一样 //
在package曾经的凝视,
将会被忽略. //
函数和变量曾经的凝视,
都会被增加到生产java代码中. package com.cmcc.demo; 

//import 引入语句 import com.cmcc.demo.ITaskCallback; 

interfaceITaskBinder { 

//函数跟java一样,
能够有0到多个參数 ,能够有一个返回值 boolean isTaskRunning(); 

voidstopRunningTask(); //參数能够是另外的一个aidl定义的接口 void registerCallback(ITaskCallback cb); 

voidunregisterCallback(ITaskCallback cb); 

//參数能够是String,
能够用in表入输入类型, out表示输出类型. 

intgetCustomerList(in String branch, out String customerList); 

}

实现接口时有几个原则: 

.抛出的异常不要返回给调用者.
跨进程抛异常处理是不可取的. 

.IPC调用是同步的。

假设你知道一个IPC服务须要超过几毫秒的时间才干完毕地话,你应该避免在Activity的主线程中调用。也就是IPC调用会挂起应用程序导致界面失去响应.
这样的情况应该考虑单起一个线程来处理. 

.不能在AIDL接口中声明静态属性。

IPC的调用步骤: 

1. 声明一个接口类型的变量,该接口类型在.aidl文件里定义。 

2. 实现ServiceConnection。 

3. 调用ApplicationContext.bindService(),并在ServiceConnection实现中进行传递. 

4. 在ServiceConnection.onServiceConnected()实现中,你会接收一个IBinder实例(被调用的Service).
调用YourInterfaceName.Stub.asInterface((IBinder)service)将參数转换为YourInterface类型。 

5. 调用接口中定义的方法。

你总要检測到DeadObjectException异常。该异常在连接断开时被抛出。它仅仅会被远程方法抛出。 

6. 断开连接。调用接口实例中的ApplicationContext.unbindService()

同一时候。我自己对AIDL实现也做了充分的測试,实现了Activity与Service之间互相调用方法,有兴趣的朋友能够下下来測试一下。

Github地址:https://github.com/BBigBoy/AndroidServiceFULLStudy

至此,关于Service的所有学习均已完毕。我们进行了Android Service的完整測试学习,主要包含生命周期測试,本地绑定执行Service实现、远程绑定执行Service的Messenger方式与AIDL方式实现 。  所有BOUND SERVICE的演示样例均实现了Service与client的交互功能。即Service能够调用client的方法,client也能够调用Service的方法。完整的项目见Github仓库:

https://github.com/BBigBoy/AndroidServiceFULLStudy

版权声明:本文博主原创文章,博客,未经同意不得转载。

AndroidService 深度分析(2)的更多相关文章

  1. const与readonly深度分析(.NET)

    前言 很多.NET的初学者对const和readonly的使用很模糊,本文就const和readonly做一下深度分析,包括: 1. const数据类型的优势 2. const数据类型的劣势 3. r ...

  2. 转:[gevent源码分析] 深度分析gevent运行流程

    [gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行 ...

  3. 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)

    写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...

  4. 深度分析如何在Hadoop中控制Map的数量

    深度分析如何在Hadoop中控制Map的数量 guibin.beijing@gmail.com 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数 ...

  5. MapReduce深度分析(二)

    MapReduce深度分析(二) 五.JobTracker分析 JobTracker是hadoop的重要的后台守护进程之一,主要的功能是管理任务调度.管理TaskTracker.监控作业执行.运行作业 ...

  6. MapReduce深度分析(一)

    MapReduce深度分析(一) 一.数据流向分析 图为MapReduce数据流向示意图 步骤1.输入文件从HDFS流向到Mapper节点.在一般情况下,存储数据的节点就是Mapper运行的节点,不需 ...

  7. 【JVM】深度分析Java的ClassLoader机制(源码级别)

    原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...

  8. 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

    原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...

  9. java集合框架(1) hashMap 简单使用以及深度分析(转)

    java.util 类 HashMap<K,V>java.lang.Object  java.util.AbstractMap<K,V>      java.util.Hash ...

随机推荐

  1. 怎么制作U盘系统/PE启动盘

    原地址:http://jingyan.baidu.com/article/3c48dd3453d05de10be358fb.html 不用光驱就能启动系统,做一个U盘启动系统就搞定,下面我给大家演示如 ...

  2. UVA1450-Airport

    题目链接 题意:有一个飞机场.有两条待飞跑到w和e.一条起飞跑道.每一时刻仅仅能起飞一架飞机,然后有w[i]和e[i]架飞机进入w和e跑道.飞机编号从0開始,问说怎样安排起飞能够使得飞机编号的最大值最 ...

  3. Android 结合实例学会AsyncTask的使用方法

    AsyncTask运行时经过四个步骤,运行四个方法:           1.onPreExecute(),执行在UI线程,能够设置或改动UI控件,如显示一个进度条           2.doInB ...

  4. UVA 10140 - Prime Distance(数论)

    10140 - Prime Distance 题目链接 题意:求[l,r]区间内近期和最远的素数对. 思路:素数打表,打到sqrt(Max)就可以,然后利用大的表去筛素数.因为[l, r]最多100W ...

  5. Android getTopActivity的方法

    使用例如以下方法能够获得top activity 的name public String getTopActivityPackageName(Context context) { String top ...

  6. 类似于qq联系人的tablview能够展开和收缩

    在.h文件中定义三个数组和一个tablview UITableView *listTable;     NSMutableArray *listArray;     NSMutableArray *p ...

  7. 用XAML做网页!!—边栏与页脚

    原文:用XAML做网页!!-边栏与页脚 此次我们来设计边栏和页脚,首先从页脚开始,其代码很简单: <Border x:Name="Footer" BorderBrush=&q ...

  8. Cantor的数表 【找规律】

    小俞同学,近期勤学苦练数学,对一种数表产生了兴趣. 数表例如以下: 1/1 1/2 1/3 1/4 1/5 2/1 2/2 2/3 2/4 3/1 3/2 3/3 4/1 4/2 5/1 她冥思苦相了 ...

  9. 图像库---Image Datasets---OpenSift源代码---openSurf源代码

    1.Computer Vision Datasets on the web http://www.cvpapers.com/datasets.html 2.Dataset Reference http ...

  10. flex 错误信息类型及解决方法

    总结一些经常出现的异常信息及处理方法(会一直持续更新): 异常1: 写actionscript3.0时遇到了错误.报错为:Error #2044: 未处理的 ioError:. text=Error ...