6、创建前台服务
前台服务的优点上面已经说明,但设置服务为前台服务,我们需要注意在 sdk 2.0 及其以后版本使用的方法是 sta rtFo reg round 与 stopFo reg round,之前版本使用的是 setFo reg round ,因此如果你应用程序的最低运行环境要求是 2.0,那么这里可以直接运用新方法,如果运行环境是2.0以下,那么为了保证向后兼容性,这里必须使用反射技术来调用新方法。
下面是我仿照 ApiDemos 重新敲的代码,对某些地方进行了修改,因此更具有说明性:
 
package com.newcj.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
public
class ForegroundService
extends Service {        
private
static
final Class[] mStartForegroundSignature =
new Class[] {                
int.
class, Notification.
class};        
private
static
final Class[] mStopForegroundSignature =
new Class[] {                
boolean.
class};        
private NotificationManager mNM;        
private Method mStartForeground;        
private Method mStopForeground;        
private Object[] mStartForegroundArgs =
new Object[2];        
private Object[] mStopForegroundArgs =
new Object[1];                 @Override        
public IBinder onBind(Intent intent) {                
return
null;        }                 @Override        
public
void onCreate() {                
super.onCreate();                mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);                
try {                        mStartForeground = ForegroundService.
class.getMethod(
"startForeground", mStartForegroundSignature);                        mStopForeground = ForegroundService.
class.getMethod(
"stopForeground", mStopForegroundSignature);                }
catch (NoSuchMethodException e) {                        mStartForeground = mStopForeground =
null;                }                
// 我们并不需要为 notification.flags 设置 FLAG_ONGOING_EVENT,因为                 // 前台服务的 notification.flags 总是默认包含了那个标志位                Notification notification = new Notification(R.drawable.icon, "Foreground Service Started.",                                System.currentTimeMillis());                PendingIntent contentIntent = PendingIntent.getActivity(this, 0,                                new Intent(this, Main.class), 0);                notification.setLatestEventInfo(this, "Foreground Service",                                "Foreground Service Started.", contentIntent);                // 注意使用    startForeground ,id 为 0 将不会显示 notification                startForegroundCompat(1, notification);        }                 @Override        public void onDestroy() {                super.onDestroy();                stopForegroundCompat(1);        }                 // 以兼容性方式开始前台服务        private void startForegroundCompat(int id, Notification n){                if(mStartForeground != null){                        mStartForegroundArgs[0] = id;                        mStartForegroundArgs[1] = n;                                                 try {                                mStartForeground.invoke(this, mStartForegroundArgs);                        } catch (IllegalArgumentException e) {                                e.printStackTrace();                        } catch (IllegalAccessException e) {                                e.printStackTrace();                        } catch (InvocationTargetException e) {                                e.printStackTrace();                        }                                                 return;                }                setForeground(true);                mNM.notify(id, n);        }                 // 以兼容性方式停止前台服务        private void stopForegroundCompat(int id){                if(mStopForeground != null){                        mStopForegroundArgs[0] = Boolean.TRUE;                                                 try {                                mStopForeground.invoke(this, mStopForegroundArgs);                        } catch (IllegalArgumentException e) {                                e.printStackTrace();                        } catch (IllegalAccessException e) {                                e.printStackTrace();                        } catch (InvocationTargetException e) {                                e.printStackTrace();                        }                        return;                }                                 //    在 setForeground 之前调用 cancel,因为我们有可能在取消前台服务之后                //    的那一瞬间被kill掉。这个时候 notification 便永远不会从通知一栏移除                mNM.cancel(id);                setForeground(false);        } }
 
 
特别注意:
1、使用 startForeground ,如果 id 为 0 ,那么 notification 将不会显示。
7、在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService
如果你只是想要启动一个后台服务长期进行某项任务那么使用 sta rtSe rvice 便可以了。如果你想要与正在运行的 Se rvice 取得联系,那么有两种方法,一种是使用 b roadcast ,另外是使用 bindSe rvice ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 B roadcast Receive r 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindSe rvice(这个时候你便同时在使用 sta rtSe rvice 和 bindSe rvice 了,这在 Activity 中更新 Se rvice 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(and roid 的 Se rvice 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindSe rvice ,这样在第一次 bindSe rvice 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是 Remote Se rvice,那么该效果会越明显(当然在 Se rvice 创建的时候会花去一定时间,你应当注意到这点)。
8、在 AndroidManifest.xml 里 Service 元素的常见选项
android:name  -------------  服务类名
android:label  --------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名
android:icon  --------------  服务的图标
android:permission  -------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
android:process  ----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
android:exported  ---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false