android Service Binder交互通信实例
最下边有源代码:
android SDK提供了Service,用于类似*nix守护进程或者windows的服务。
Service有两种类型:
- 本地服务(Local Service):用于应用程序内部
- 远程服务(Remote Sercie):用于android系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
编写不需和Activity交互的本地服务示例
本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。这里写了一个计数服务的类,每秒钟为计数器加一。在服务类的内部,还创建了一个线程,用于实现后台执行上述业务逻辑。
package
com.easymorse;
import
android.app.Service;
import
android.content.Intent;
import
android.os.IBinder;
import
android.util.Log;
public
class
CountService
extends
Service {
private
boolean
threadDisable;
private
int
count;
@Override
public
IBinder onBind(Intent intent) {
return
null
;
}
@Override
public
void
onCreate() {
super
.onCreate();
new
Thread(
new
Runnable() {
@Override
public
void
run() {
while
(
!
threadDisable) {
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
}
count
++
;
Log.v(
"
CountService
"
,
"
Count is
"
+
count);
}
}
}).start();
}
@Override
public
void
onDestroy() {
super
.onDestroy();
this
.threadDisable
=
true
;
Log.v(
"
CountService
"
,
"
on destroy
"
);
}
public
int
getCount() {
return
count;
}
}
需要将该服务注册到配置文件AndroidManifest.xml中,否则无法找到:
<?
xml version="1.0" encoding="utf-8"
?>
<
manifest
xmlns:android
="http://schemas.android.com/apk/res/android"
package
="com.easymorse"
android:versionCode
="1"
android:versionName
="1.0"
>
<
application
android:icon
="@drawable/icon"
android:label
="@string/app_name"
>
<
activity
android:name
=".LocalServiceDemoActivity"
android:label
="@string/app_name"
>
<
intent-filter
>
<
action
android:name
="android.intent.action.MAIN"
/>
<
category
android:name
="android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<
service
android:name
="CountService"
/>
</
application
>
<
uses-sdk
android:minSdkVersion
="3"
/>
</
manifest/>
在Activity中启动和关闭本地服务。
package
com.easymorse;
import
android.app.Activity;
import
android.content.Intent;
import
android.os.Bundle;
public
class
LocalServiceDemoActivity
extends
Activity {
/**
Called when the activity is first created.
*/
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
this
.startService(
new
Intent(
this
, CountService.
class
));
}
@Override
protected
void
onDestroy() {
super
.onDestroy();
this
.stopService(
new
Intent(
this
, CountService.
class
));
}
}
可通过日志查看到后台线程打印的计数内容。
编写本地服务和Activity交互的示例
上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。
具体做法是,服务类需要增加接口,比如ICountService,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类
需要继承Binder类并实现ICountService接口。还有,就是要实现Service的onBind方法,不能只传回一个null了。
这是新建立的接口代码:
package
com.easymorse;
public
interface
ICountService {
public
abstract
int
getCount();
}
修改后的CountService代码:
package
com.easymorse;
import
android.app.Service;
import
android.content.Intent;
import
android.os.Binder;
import
android.os.IBinder;
import
android.util.Log;
public
class
CountService
extends
Service
implements
ICountService {
private
boolean
threadDisable;
private
int
count;
private
ServiceBinder serviceBinder
=
new
ServiceBinder();
public
class
ServiceBinder
extends
Binder
implements
ICountService{
@Override
public
int
getCount() {
return
count;
}
}
@Override
public
IBinder onBind(Intent intent) {
return
serviceBinder;
}
@Override
public
void
onCreate() {
super
.onCreate();
new
Thread(
new
Runnable() {
@Override
public
void
run() {
while
(
!
threadDisable) {
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
}
count
++
;
Log.v(
"
CountService
"
,
"
Count is
"
+
count);
}
}
}).start();
}
@Override
public
void
onDestroy() {
super
.onDestroy();
this
.threadDisable
=
true
;
Log.v(
"
CountService
"
,
"
on destroy
"
);
}
/*
(non-Javadoc)
* @see com.easymorse.ICountService#getCount()
*/
public
int
getCount() {
return
count;
}
}
服务的注册也要做改动,AndroidManifest.xml文件:
<?
xml version="1.0" encoding="utf-8"
?>
<
manifest
xmlns:android
="http://schemas.android.com/apk/res/android"
package
="com.easymorse"
android:versionCode
="1"
android:versionName
="1.0"
>
<
application
android:icon
="@drawable/icon"
android:label
="@string/app_name"
>
<
activity
android:name
=".LocalServiceDemoActivity"
android:label
="@string/app_name"
>
<
intent-filter
>
<
action
android:name
="android.intent.action.MAIN"
/>
<
category
android:name
="android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<
service
android:name
="CountService"
>
<
intent-filter
>
<
action
android:name
="com.easymorse.CountService"
/>
</
intent-filter
>
</
service
>
</
application
>
<
uses-sdk
android:minSdkVersion
="3"
/>
</
manifest
>
Acitity代码不再通过startSerivce和stopService启动关闭服务,另外,需要通过ServiceConnection的内部类实现来连接Service和Activity。
package
com.easymorse;
import
android.app.Activity;
import
android.content.ComponentName;
import
android.content.Intent;
import
android.content.ServiceConnection;
import
android.os.Bundle;
import
android.os.IBinder;
import
android.util.Log;
public
class
LocalServiceDemoActivity
extends
Activity {
private
ServiceConnection serviceConnection
=
new
ServiceConnection() {
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
countService
=
(ICountService) service;
Log.v(
"
CountService
"
,
"
on serivce connected, count is
"
+
countService.getCount());
}
@Override
public
void
onServiceDisconnected(ComponentName name) {
countService
=
null
;
}
};
private
ICountService countService;
/**
Called when the activity is first created.
*/
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
this
.bindService(
new
Intent(
"
com.easymorse.CountService
"
),
this
.serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected
void
onDestroy() {
this
.unbindService(serviceConnection);
super
.onDestroy(); //注意先后
}
}
编写传递基本型数据的远程服务
上面的示例,可以扩展为,让其他应用程序复用该服务。这样的服务叫远程(remote)服务,实际上是进程间通信(RPC)。
这时需要使用android接口描述语言(AIDL)来定义远程服务的接口,而不是上述那样简单的java接口。扩展名为aidl而不是java。
可用上面的ICountService改动而成ICountSerivde.aidl,eclipse会自动生成相关的java文件。
package com.easymorse;
interface
ICountService {
int
getCount();
}
编写服务(Service)类,稍有差别,主要在binder是通过远程获得的,需要通过桩(Stub)来获取。桩对象是远程对象的本地代理。
package
com.easymorse;
import
android.app.Service;
import
android.content.Intent;
import
android.os.IBinder;
import
android.os.RemoteException;
import
android.util.Log;
public
class
CountService
extends
Service {
private
boolean
threadDisable;
private
int
count;
private
ICountService.Stub serviceBinder
=
new
ICountService.Stub() {
@Override
public
int
getCount()
throws
RemoteException {
return
count;
}
};
@Override
public
IBinder onBind(Intent intent) {
return
serviceBinder;
}
@Override
public
void
onCreate() {
super
.onCreate();
new
Thread(
new
Runnable() {
@Override
public
void
run() {
while
(
!
threadDisable) {
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
}
count
++
;
Log.v(
"
CountService
"
,
"
Count is
"
+
count);
}
}
}).start();
}
@Override
public
void
onDestroy() {
super
.onDestroy();
this
.threadDisable
=
true
;
Log.v(
"
CountService
"
,
"
on destroy
"
);
}
}
配置文件AndroidManifest.xml和上面的类似,没有区别。
在Activity中使用服务的差别不大,只需要对ServiceConnection中的调用远程服务的方法时,要捕获异常。
private
ServiceConnection serviceConnection
=
new
ServiceConnection() {
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
countService
=
(ICountService) service;
try
{
Log.v(
"
CountService
"
,
"
on serivce connected, count is
"
+
countService.getCount());
}
catch
(RemoteException e) {
throw
new
RuntimeException(e);
}
}
@Override
public
void
onServiceDisconnected(ComponentName name) {
countService
=
null
;
}
};
这样就可以在同一个应用程序中使用远程服务的方式和自己定义的服务交互了。
如果是另外的应用程序使用远程服务,需要做的是复制上面的aidl文件和相应的包构到应用程序中,其他调用等都一样。
编写传递复杂数据类型的远程服务
远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:
- android支持String和CharSequence
- 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
- android允许传递实现Parcelable接口的类,需要import;
- android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
- 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。
这里将前面的例子中返回的int数据改为复杂数据类型:
package
com.easymorse;
import
android.os.Parcel;
import
android.os.Parcelable;
public
class
CountBean
implements
Parcelable {
public
static
final
Parcelable.Creator
<
CountBean
>
CREATOR
=
new
Creator
<
CountBean
>
() {
@Override
public
CountBean createFromParcel(Parcel source) {
CountBean bean
=
new
CountBean();
bean.count
=
source.readInt();
return
bean;
}
@Override
public
CountBean[] newArray(
int
size) {
return
new
CountBean[size];
}
};
public
int
count;
@Override
public
void
writeToParcel(Parcel dest,
int
flags) {
dest.writeInt(
this
.count);
}
@Override
public
int
describeContents() {
return
0
;
}
}
然后,需要在相同包下建一个同名的aidl文件,用于android生成相应的辅助文件:
package
com.easymorse;
parcelable CountBean;
这一步是android 1.5后的变化,无法通过adt生成aidl,也不能用一个比如全局的project.aidl文件,具体见:
http://www.anddev.org/viewtopic.php?p=20991
然后,需要在服务的aidl文件中修改如下:
package
com.easymorse;
import
com.easymorse.CountBean;
interface
ICountService {
CountBean getCount();
}
其他的改动很小,只需将CountService和调用CountService的部分修改为使用CountBean即可
分享到:
相关推荐
Activity可以通过bindService()方法来与Service建立绑定关系,这种绑定方式主要用于当Activity需要与Service进行频繁交互或需要获取Service提供的接口时。绑定后,Activity可以通过返回的IBinder对象与Service进行...
总的来说,Android Service的源码学习涉及了Service生命周期、Service与客户端交互、进程通信、线程管理等多个方面。通过对这些知识点的深入理解和实践,开发者可以更好地设计和优化自己的应用程序,提升用户体验。
- **Activity与Service**:客户端通常由UI(User Interface)活动(Activity)触发服务请求,Service用于在后台执行长时间任务,如网络通信。 - **AsyncTask**:用于在非UI线程中执行耗时操作,避免阻塞主线程,...
Service与Activity之间的通信通常有以下三种方法: 1. **接口回调**:这是一种直接的通信方式,通过定义一个接口,Service在数据变化时调用接口的方法,将信息传递给Activity。Activity作为Service的观察者,实现这...
在Android源码中,这个选择过程主要由`ActivityResolver`类和`ActivityManagerService`(AMS)完成。AMS是系统服务,负责管理所有应用程序的Activity、服务和广播接收器等。当一个Intent被广播时,AMS会使用`...
在Android开发中,Activity是应用程序的基本构建块,用于展示用户界面和处理用户交互。Activity跳转是Android应用中常见的操作,用于在不同的界面之间切换。本篇将详细讲解`android入门activity跳转源代码`的相关...
在Android应用开发中,Activity是构成应用程序的基本组件之一,它代表了用户可见并可以与之交互的屏幕。Activity跳转与操作是Android开发者必须掌握的关键技能,涉及到Intent、生命周期、数据传递等多个方面。本资源...
本篇文章将深入探讨Service的两种主要应用:`startService`和`bindService`,并结合提供的源码分析进行详细解释。 首先,`startService`是启动一个Service的方式,它适合那些不需要与启动Service的应用组件直接交互...
在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的操作,不与用户交互。本资源提供了关于Android中Service的源码,重点展示了Service的生命周期以及如何在Service中播放音乐。通过分析和学习这...
5. **Intent机制**:Intent是Android系统中实现组件间通信的重要手段,源码中会展示如何创建Intent来启动Activity、Service或其他组件。 6. **数据存储**:Android提供了多种数据存储方式,如SharedPreferences、...
AIDL(Android Interface Definition Language)是Android提供的一种工具,用于方便开发者定义服务接口,实现不同进程间的交互。本篇文章将深入探讨如何通过AIDL在Activity与Service之间进行进程间通信。 首先,...
在Android应用开发中,Activity是用户界面的基本组件,它负责展示屏幕上的内容并处理与用户的交互。Activity的生命周期是Android开发者必须深入理解的关键概念,因为它直接影响到应用的性能、资源管理和用户体验。本...
10. **媒体库集成**:如果源码更进一步,可能会集成Android的MediaStore类,以系统化的方式访问设备上的音乐库,这样可以获取更丰富的音乐信息。 11. **音量控制**:使用AudioManager类来管理音量,包括媒体音量和...
6. **Android系统服务**:如Package Manager Service(PMS)用于管理应用的安装、更新和卸载,Activity Manager Service(AMS)则负责调度用户的活动和任务,这些都是与Launcher交互的关键服务。 7. **自定义启动器...
在Android系统中,Activity是应用程序的基本组件之一,用于与用户交互和展示界面。当我们需要根据不同的情况启动同一个Activity时,通常会通过Intent的Action属性来区分不同的启动意图。本压缩包文件提供了关于如何...
`Android Hook Activity 启动劫持`是一种高级技术,它允许开发者利用动态代理(Dynamic Proxy)技术来拦截并控制AMS的行为,从而在不修改系统源码的情况下,实现对Activity启动流程的监控或修改。 首先,我们需要...
在Android开发中,Service和Activity是两个非常重要的组件。Service主要负责在后台执行长时间运行的任务,而Activity则作为用户交互的界面。它们之间的通信是Android应用中常见的需求,例如播放音乐、下载数据等。本...
在Android应用开发中,Service是四大组件之一,它在后台长时间运行,即使用户与应用程序的交互界面已经关闭。Service主要用于执行耗时的操作,如音乐播放、网络通信等。本源码例子将帮助初学者理解如何在Android项目...