android service 精辟解说

本地服务

所谓本地服务,其实就是完全服务于一个进程的组件。本地服务的这种特性决定了它有特别的启动方式。通常这类服务的典型案例,就是邮件轮询。
  • 调用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时是异步操作,目标服务如果未在后台运行,那么在链接过程中会被启动。
下面我们来作一个调用模拟,可以看到图例大概的结构是这样的。 服务端(RPCService)
  • 定义AIDL接口并不复杂,只要写个以aidl后缀的文件放在src/package/目录下,而系统就会自动生成一个文件在gen/package/目录下(这个功能是eclipse ADT 自行完成的)。
  • 当生成了绑定文件后,我们需要写个一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" ?>
< manifest xmlns:android = "http://schemas.android.com/apk/res/android"
       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)。
客服端(RPClient)
  • 首先,你需要模拟一个目标服务相同的包(目录结构),并且将AIDL文件复制在该包中,这样Client就获得了连接Service的契约(AIDL)。
  • 接下来就要开始调用服务了。
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);
         }
     }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值