【转】Service创建有两种方法: startService或者bindService
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
?
2). Remote 服务绑定:Remote 的服务绑定由于服务是在另外一个进程,因此需要用到 android 的 IPC 机制。这将又是一个很长的话题,因此,我打算写另外一篇 android 的 IPC 机制分析 ,并在其中进行详述,然后在这里更新链接,敬请关注。
?
特别注意:
1、Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected 不会被调用,但你任然需要使用 unbindService 函数断开它,这样 Service 才会停止。
?
6、创建前台服务
前台服务的优点上面已经说明,但设置服务为前台服务,我们需要注意在 sdk 2.0 及其以后版本使用的方法是 startForeground 与 stopForeground,之前版本使用的是 setForeground ,因此如果你应用程序的最低运行环境要求是 2.0,那么这里可以直接运用新方法,如果运行环境是2.0以下,那么为了保证向后兼容性,这里必须使用反射技术来调用新方法。
下面是我仿照 ApiDemos 重新敲的代码,对某些地方进行了修改,因此更具有说明性:
001package com.newcj.test; 002?003import java.lang.reflect.InvocationTargetException; 004import java.lang.reflect.Method; 005?006import android.app.Notification; 007import android.app.NotificationManager; 008import android.app.PendingIntent; 009import android.app.Service; 010import android.content.Context; 011import android.content.Intent; 012import android.os.IBinder; 013?014public class ForegroundService extends Service { 015?016private static final Class[] mStartForegroundSignature = new Class[] { 017int.class, Notification.class}; 018private static final Class[] mStopForegroundSignature = new Class[] { 019boolean.class}; 020private NotificationManager mNM; 021private Method mStartForeground; 022private Method mStopForeground; 023private Object[] mStartForegroundArgs = new Object[2]; 024private Object[] mStopForegroundArgs = new Object[1]; 025?026@Override027public IBinder onBind(Intent intent) { 028return null; 029}030?031@Override032public void onCreate() { 033super.onCreate(); 034mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);035try { 036mStartForeground = ForegroundService.class.getMethod("startForeground", mStartForegroundSignature); 037mStopForeground = ForegroundService.class.getMethod("stopForeground", mStopForegroundSignature); 038} catch (NoSuchMethodException e) { 039mStartForeground = mStopForeground = null; 040}041// 我们并不需要为 notification.flags 设置 FLAG_ONGOING_EVENT,因为042// 前台服务的 notification.flags 总是默认包含了那个标志位043Notification notification = new Notification(R.drawable.icon, "Foreground Service Started.", 044System.currentTimeMillis());045PendingIntent contentIntent = PendingIntent.getActivity(this, 0, 046new Intent(this, Main.class), 0); 047notification.setLatestEventInfo(this, "Foreground Service", 048"Foreground Service Started.", contentIntent); 049// 注意使用 startForeground ,id 为 0 将不会显示 notification050startForegroundCompat(1, notification); 051}052?053@Override054public void onDestroy() { 055super.onDestroy(); 056stopForegroundCompat(1); 057}058?059// 以兼容性方式开始前台服务060private void startForegroundCompat(int id, Notification n){ 061if(mStartForeground != null){ 062mStartForegroundArgs[0] = id; 063mStartForegroundArgs[1] = n; 064?065try { 066mStartForeground.invoke(this, mStartForegroundArgs); 067} catch (IllegalArgumentException e) { 068e.printStackTrace();069} catch (IllegalAccessException e) { 070e.printStackTrace();071} catch (InvocationTargetException e) { 072e.printStackTrace();073}074?075return; 076}077setForeground(true); 078mNM.notify(id, n);079}080?081// 以兼容性方式停止前台服务082private void stopForegroundCompat(int id){ 083if(mStopForeground != null){ 084mStopForegroundArgs[0] = Boolean.TRUE; 085?086try { 087mStopForeground.invoke(this, mStopForegroundArgs); 088} catch (IllegalArgumentException e) { 089e.printStackTrace();090} catch (IllegalAccessException e) { 091e.printStackTrace();092} catch (InvocationTargetException e) { 093e.printStackTrace();094}095return; 096}097?098// 在 setForeground 之前调用 cancel,因为我们有可能在取消前台服务之后099// 的那一瞬间被kill掉。这个时候 notification 便永远不会从通知一栏移除100mNM.cancel(id);101setForeground(false); 102}103?104}特别注意:
1、使用 startForeground ,如果 id 为 0 ,那么 notification 将不会显示。
7、在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService
如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。
8、在 AndroidManifest.xml 里 Service 元素的常见选项
android:name ------------- 服务类名
android:label -------------- 服务的名字,如果此项不设置,那么默认显示的服务名则为类名
android:icon -------------- 服务的图标
android:permission ------- 申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
android:process ---------- 表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
android:enabled ---------- 如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
android:exported --------- 表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false
本文代码下载地址:http://files.cnblogs.com/newcj/ServiceTest.zip