本地服务
所谓本地服务,其实就是完全服务于一个进程的组件。本地服务的这种特性决定了它有特别的启动方式。通常这类服务的典型案例,就是邮件轮询。
- 调用Context.startService()启动服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package
net.bpsky;
import
android.app.Notification;
import
android.app.NotificationManager;
import
android.app.PendingIntent;
import
android.app.Service;
import
android.content.Intent;
import
android.os.IBinder;
public
class
DoudingService
extends
Service {
private
NotificationManager notificationMgr;
@Override
public
IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return
null
;
}
@Override
public
void
onCreate(){
super
.onCreate();
notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage(
"Starting Background Service!"
);
Thread thr =
new
Thread(
null
,
new
ServiceWorker(),
"BackgroundService"
);
thr.start();
}
class
ServiceWorker
implements
Runnable{
public
void
run(){
// bla bla bla...
}
}
@Override
public
void
onDestroy(){
displayNotificationMessage(
"Stopping Background Service"
);
super
.onDestroy();
}
@Override
public
void
onStart(Intent intent,
int
startId){
super
.onStart(intent, startId);
}
private
void
displayNotificationMessage(String message){
Notification notification =
new
Notification(R.drawable.note,message,System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(
this
,
0
,
new
Intent(
this
,FeedActivity.
class
),
0
);
notification.setLatestEventInfo(
this
,
"background Service"
, message, contentIntent);
notificationMgr.notify(R.id.app_notification_id,notification);
}
}
|
远程服务
支持onBind()方法的,就是远程服务。远程服务并不是说一定要远程访问,而是支持(RPC,Remote Procedure Call,远程过程调用)。这类服务的典型案例就是应用程序之间执行通信。比如:路由服务,将信息转发至其它应用程序。远程服务最重要的一个特性就是需要AIDL(Android Interface Definition Language)向客户端定义自身。- 定义AIDL接口
- 调用Context.bindService()绑定调用
- 优势在于允许不同进程进行绑定调用
- 在使用bindService时是异步操作,目标服务如果未在后台运行,那么在链接过程中会被启动。
![](http://www.bpsky.net/static/upload/postfiles/1310609819.png)
- 定义AIDL接口并不复杂,只要写个以aidl后缀的文件放在src/package/目录下,而系统就会自动生成一个文件在gen/package/目录下(这个功能是eclipse ADT 自行完成的)。
![](http://www.bpsky.net/static/upload/postfiles/1310455321.png)
- 当生成了绑定文件后,我们需要写个一Service并实现接口(byron认为书中的例子是在Service中实现了一个内部类,并在内部类中实现了接口方法,再由Service.onBind将实例返回)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package
net.bpsky.service;
import
android.app.Service;
import
android.content.Intent;
import
android.os.IBinder;
import
android.os.RemoteException;
import
android.util.Log;
public
class
RPCService
extends
Service {
private
static
final
String TAG =
"RPCService"
;
public
class
RPCServiceImpl
extends
IRPCService.Stub{
@Override
public
int
getValue(String text)
throws
RemoteException{
Log.v(TAG,
"getValue called for "
+text);
return
5
;
}
}
@Override
public
IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.v(TAG,
"onBind() called"
);
return
new
RPCServiceImpl();
}
@Override
public
void
onCreate(){
super
.onCreate();
Log.v(TAG,
"onCreate() called"
);
}
@Override
public
void
onDestroy(){
super
.onDestroy();
Log.v(TAG,
"onDestroy() called"
);
}
@Override
public
void
onStart(Intent intent,
int
startId){
super
.onStart(intent,startId);
Log.v(TAG,
"onStart() called"
);
}
}
|
- 因为服务本身是没有任何界面的,所以在本模拟中activity是多余的存在,有了服务当然还要在AndroidManifest.xml申明。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
package
=
"net.bpsky.service"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"10"
/>
<
application
android:icon
=
"@drawable/icon"
android:label
=
"@string/app_name"
>
<
activity
android:name
=
".RPCServiceActivity"
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
=
"RPCService"
>
<
intent-filter
>
<
action
android:name
=
"net.bpsky.service.IRPCService"
/>
</
intent-filter
>
</
service
>
</
application
>
</
manifest
>
|
- 现在我们完成了一个服务端模拟推送中心。但它并没有任何作用,在本例中业务处理只是简单的在getValue方法中返回了int(5)。
- 首先,你需要模拟一个目标服务相同的包(目录结构),并且将AIDL文件复制在该包中,这样Client就获得了连接Service的契约(AIDL)。
![](http://www.bpsky.net/static/upload/postfiles/1310610492.png)
- 接下来就要开始调用服务了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
package
net.bpsky.client;
import
net.bpsky.service.*;
import
android.app.Activity;
import
android.content.ComponentName;
import
android.content.Context;
import
android.content.Intent;
import
android.content.ServiceConnection;
import
android.os.Bundle;
import
android.os.IBinder;
import
android.os.RemoteException;
import
android.util.Log;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.Toast;
public
class
RPClientActivity
extends
Activity {
protected
static
final
String TAG =
"Client"
;
private
IRPCService serviceInstance =
null
;
private
Button bindBtn;
private
Button callBtn;
private
Button unbindBtn;
/** Called when the activity is first created. */
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
bindBtn = (Button)findViewById(R.id.bindService);
bindBtn.setOnClickListener(
new
OnClickListener(){
@Override
public
void
onClick(View v){
bindService(
new
Intent(IRPCService.
class
.getName()),serviceConn,Context.BIND_AUTO_CREATE);
bindBtn.setEnabled(
false
);
callBtn.setEnabled(
true
);
unbindBtn.setEnabled(
true
);
}
});
callBtn = (Button)findViewById(R.id.callService);
callBtn.setOnClickListener(
new
OnClickListener(){
@Override
public
void
onClick(View v){
callService();
}
});
callBtn.setEnabled(
false
);
unbindBtn = (Button)findViewById(R.id.unbindService);
unbindBtn.setOnClickListener(
new
OnClickListener(){
@Override
public
void
onClick(View v){
unbindService(serviceConn);
bindBtn.setEnabled(
true
);
callBtn.setEnabled(
false
);
unbindBtn.setEnabled(
false
);
}
});
unbindBtn.setEnabled(
false
);
}
private
ServiceConnection serviceConn =
new
ServiceConnection(){
@Override
public
void
onServiceConnected(ComponentName name,IBinder service){
Log.v(TAG,
"onServiceConnected() called"
);
serviceInstance = IRPCService.Stub.asInterface(service);
callService();
}
@Override
public
void
onServiceDisconnected(ComponentName name){
Log.v(TAG,
"onServiceDisconnected() called"
);
serviceInstance =
null
;
}
};
private
void
callService(){
try
{
int
val = serviceInstance.getValue(
"test"
);
Toast.makeText(RPClientActivity.
this
,
"Value from service is "
+val, Toast.LENGTH_LONG).show();
}
catch
(RemoteException ee){
Log.e(TAG,ee.getMessage(),ee);
}
}
}
|
- 华丽的去测试吧。