Android SDK提供了两种类型的Service,用于类似*nix守护进程或者windows的服务
1. 本地服务Local Service :用于应用程序内部
2. 远程服务Remote Service :用于android系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程式比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
后者可被其他应用程序服用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
不需要和Activitye交互的本地服务
本地服务编写比较简单。首先,要创建一个Service类,该类继承android的Service类。然后在Activity中的onCreate和onDestory中分别执行以下语句开启服务和停止服务。
this .startService( new Intent( this , ServiceImpl. class));
this .stopService( new Intent( this , ServiceImpl. class));
需要和Activity交互的远程服务
上面的示例是通过startService和stopService启动关闭服务的。适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用。需要使用bind和unbind方法。
具体做法是,服务类需要增加接口,比如ServiceInterface,另外,服务类需要有一个内部类,这样可以方便访问外部类的封装数据,这个内部类需要继承Binder类并实现ServiceInterface接口。还有,就是要实现Service的onBind方法,不能只传回一个null了。
在android的musicplayer源码中MediaPlaybackService使用了以上的服务方式,针对该源码进行分析:
首先需要了解进程间通信、需要AIDL(以及Binder)
关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html
关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html
以及Binder:docs/reference/android/os/Binder.html
manifest中Service的语法,见docs/guide/topics/manifest /service-element.html
以上转自http://blog.csdn.net/saintswordsman/archive/2010/01/05/5130947.aspx
步骤一:建立aidl文件
通过aidl.exe会在gen中生成该service类,该类中的成员变量stub实现了以下功能:
extends Binder implements ServiceInterface,源码如下
interface IMediaPlaybackService { void openfile(String path); void openfileAsync(String path); void open(in int [] list, int position); ...................//接口方法 }
public interface IMediaPlaybackService extends android.os.IInterface { /**生成binder类 */ public static abstract class Stub extends android.os.Binder implements com.android.mymusic.IMediaPlaybackService { private static final java.lang.String DESCRIPTOR = "com.android.mymusic.IMediaPlaybackService"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } ................... ................... ...................//binder 方法 } public void openfile(java.lang.String path) throws android.os.RemoteException; ................... ...................//接口方法 ................... }
步骤二:编写服务的实现类MediaPlaybackService
public class MediaPlaybackService extends Service { ...... @Override public IBinder onBind(Intent intent) { mDelayedStopHandler.removeCallbacksAndMessages(null); mServiceInUse = true; return mBinder; } private final IMediaPlaybackService.Stub mBinder = new IMediaPlaybackService.Stub() { ...................//实现接口方法 }; }
步骤三:编写一个消费这个服务的Activity:MediaPlaybackActivity:(除此之外还有其他类)
public class MediaPlaybackActivity extends Activity implements MusicUtils.Defs, View.OnTouchListener, View.OnLongClickListener { private IMediaPlaybackService mService = null; @Override public void onStart() { super.onStart(); ...................//其他代码 if (false == MusicUtils.bindToService(this, serviecConnection)) { // something went wrong ...................//其他代码 } private ServiceConnection serviecConnection = new ServiceConnection() { public void onServiceConnected(ComponentName classname, IBinder obj) { mService = IMediaPlaybackService.Stub.asInterface(obj); if (MusicUtils.sService == null) { MusicUtils.sService = mService; ...................//其他代码 } } public void onServiceDisconnected(ComponentName classname) { } }; } //MusicUtils类:定义了播放器所需要的操作以及service和Activity之间的相互作用的操作 public class MusicUtils { ...................//其他代码 public static boolean bindToService(Context context, ServiceConnection callback) { context.startService(new Intent(context, MediaPlaybackService.class)); ServiceBinder sb = new ServiceBinder(callback); sConnectionMap.put(context, sb); return context.bindService((new Intent()).setClass(context, MediaPlaybackService.class), sb, 0); } ...................//其他代码 }
需要注意:
远程服务往往不只是传递java基本数据类型。这时需要注意android的一些限制和规定:
以下转自http://yangguangfu.iteye.com/blog/699306
1. android支持String和CharSequence
2. 如果需要在aidl中使用其他aidl接口类型,需要import,即使是在相同包结构下;
3. android允许传递实现Parcelable接口的类,需要import;
4.android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者上述三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;
非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。