今天是开始记录学习的第二天,今天记录的东西大部分是以前学过的,今天在这里把它梳理成文,主要还是对以前学习的一个总结和回顾。知识除了积累还要经常温故,古语有云:温故而知新。
1.Service的启动一般都是 某个组件调用startService 或者 bindService
2. 通过 Android特有的 Binder IPC机制 通知 ActivityServiceManager ,
3.Ams就会直接通过Binder IPC机制 通知 Service 所在的ActivityThread 把这个服务启动起来 (把这个Service的class文件load到内存)
4.如果是BindService ,Ams还会从Service哪里取到一个binder 然后同样通过IPC传给启动他的Activity ,Activity 拿到这个binder后就可以和Service通讯了
ok 下面注重介绍的是Service的用法
1.通过startService方式启动的Service
a 生命周期
context.startService() 的生命周期
context.startService() -> onCreate() -> onStart() -> Service running -> context.stopService() -> onDestroy() -> Service stop
如果Service还没有运行,则android先调用onCreate(),然后调用onStart();
如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。
如果stopService的时候会直接onDestroy,如果是调用者自己直接退出而没有调用stopService或者Service.stopSelfResult()的话,Service会一直在后台运行,该Service的调用者再启动起来后可以通过stopService或者Service.stopSelfResult()关闭Service。
所以调用startService的生命周期为:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
package
com.example.testservice;
public
class
MainActivity
extends
Activity {
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Intent service = new Intent(this, MyService.class);//通过组件名调用
Intent service =
new
Intent(
"com.example.testservice.MYSERVICEFROMACTION"
);
// 隐式调用,注意在manifest中指定action
startService(service);
}
}
|
01
02
03
04
05
06
07
08
09
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
|
public
class
MyService
extends
Service {
String TAG =
"MyService"
;
@Override
public
void
onCreate() {
new
AsyncTask
@Override
protected
Void doInBackground(Void... params) {
for
(
int
i =
0
; i <
1000
; i++) {
try
{
Thread.sleep(
1000
);
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, i +
"service"
);
}
return
null
;
}
}.execute();
super
.onCreate();
}
@Override
public
IBinder onBind(Intent intent) {
Log.e(TAG,
"onBind"
);
return
null
;
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<
application
android:allowBackup
=
"true"
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
android:theme
=
"@style/AppTheme"
>
<
activity
android:name
=
"com.example.testservice.MainActivity"
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
=
"com.example.testservice.MyService"
>
<
intent-filter
>
<
action
android:name
=
"com.example.testservice.MYSERVICEFROMACTION"
/>
intent-filter
>
service
>
application
>
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
class
MainActivity
extends
Activity {
public
MyService myService;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent service =
new
Intent(
this
, MyService.
class
);
// 通过组件名调用
bindService(service, conn, Context.BIND_AUTO_CREATE);
}
// Ams开启的Service后 会通知MainActivity在不同的时机执行这些回调
private
ServiceConnection conn =
new
ServiceConnection() {
@Override
public
void
onServiceDisconnected(ComponentName name) {
}
// 在这里可以拿到Service中设置返回的东西,一般是一个Service对象
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.MyBinder) service).getService();
//拿到了Service的引用
Toast.makeText(MainActivity.
this
, myService.getVal(),
10
).show();
}
};
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
package
com.example.testservice;
import
android.app.Service;
import
android.content.Intent;
import
android.os.AsyncTask;
import
android.os.Binder;
import
android.os.IBinder;
import
android.util.Log;
public
class
MyService
extends
Service {
String TAG =
"MyService"
;
public
String getVal() {
return
"Hi I am from Service!"
;
}
// 封装后Activity就可以通过getService方法获取这个服务实例了
@Override
public
IBinder onBind(Intent intent) {
Log.e(TAG,
"onBind"
);
return
new
MyBinder();
}
public
class
MyBinder
extends
Binder {
MyService getService() {
return
MyService.
this
;
}
}
}
|
01
02
03
|
public
interface
IMyService {
public
String getVal();
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
class
MainActivity
extends
Activity {
public
IMyService myService;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent service =
new
Intent(
this
, MyService.
class
);
// 通过组件名调用
bindService(service, conn, Context.BIND_AUTO_CREATE);
}
// Ams开启的Service后 会通知MainActivity在不同的时机执行这些回调
private
ServiceConnection conn =
new
ServiceConnection() {
@Override
public
void
onServiceDisconnected(ComponentName name) {
}
// 在这里可以拿到Service中设置返回的东西,一般是一个Service对象
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.MyBinder) service).getService();
Log.e(
"TAG"
, name.toString());
// 组件的ComponentName
Toast.makeText(MainActivity.
this
, myService.getVal(),
10
).show();
}
};
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
MyService
extends
Service
implements
IMyService {
String TAG =
"MyService"
;
public
String getVal() {
return
"Hi I am from Service!"
;
}
// 封装后Activity就可以通过getService方法获取这个服务实例了
@Override
public
IBinder onBind(Intent intent) {
Log.e(TAG,
"onBind"
);
return
new
MyBinder();
}
public
class
MyBinder
extends
Binder {
MyService getService() {
return
MyService.
this
;
}
}
}
|
01
02
03
04
|
public
int
onStartCommand(Intent intent,
int
flags,
int
startId) {
onStart(intent, startId);
return
mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
|
01
02
03
04
|
case
SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"serviceStart"
);
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
01
02
03
04
05
06
07
08
09
10
11
|
public
final
void
scheduleServiceArgs(IBinder token,
boolean
taskRemoved,
int
startId,
int
flags ,Intent args) {
ServiceArgsData s =
new
ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
queueOrSendMessage(H.SERVICE_ARGS, s);
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
private
final
void
sendServiceArgsLocked(ServiceRecord r,
boolean
oomAdjusted) {
final
int
N = r.pendingStarts.size();
if
(N ==
0
) {
return
;
}
while
(r.pendingStarts.size() >
0
) {
try
{
ServiceRecord.StartItem si = r.pendingStarts.remove(
0
);
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if
(si.neededGrants !=
null
) {
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
int
flags =
0
;
if
(si.deliveryCount >
1
) {
flags |= Service.START_FLAG_RETRY;
}
if
(si.doneExecutingCount >
0
) {
flags |= Service.START_FLAG_REDELIVERY;
}
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
}
catch
(RemoteException e) {
....
}
}
|
01
02
03
04
05
06
07
08
09
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
|
private
void
handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service =
null
;
try
{
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
}
catch
(Exception e) {
... ...
}
try
{
if
(localLOGV) Slog.v(TAG,
"Creating service "
+ data.info.name);
ContextImpl context =
new
ContextImpl();
context.init(packageInfo,
null
,
this
);
Application app = packageInfo.makeApplication(
false
, mInstrumentation);
context.setOuterContext(service);
service.attach(context,
this
, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try
{
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token,
0
,
0
,
0
);
}
catch
(RemoteException e) {
// nothing to do.
}
}
catch
(Exception e) {
... ...
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
private
void
handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if
(s !=
null
) {
try
{
if
(data.args !=
null
) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
int
res;
if
(!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
}
else
{
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
QueuedWork.waitToFinish();
try
{
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token,
1
, data.startId, res);
//重新调用了 serviceDoneExecuting
}
catch
(RemoteException e) {
// nothing to do.
}
ensureJitEnabled();
}
catch
(Exception e) {
if
(!mInstrumentation.onException(s, e)) {
throw
new
RuntimeException(
"Unable to start service "
+ s
+
" with "
+ data.args +
": "
+ e.toString(), e);
}
}
}
}
|
01
02
03
04
05
06
07
08
09
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
|
void
serviceDoneExecutingLocked(ServiceRecord r,
int
type,
int
startId,
int
res) {
boolean
inStopping = mStoppingServices.contains(r);
if
(r !=
null
) {
if
(type ==
1
) {
// This is a call from a service start... take care of
// book-keeping.
r.callStart =
true
;
switch
(res) {
case
Service.START_STICKY_COMPATIBILITY:
case
Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId,
true
);
// Don't stop if killed.
r.stopIfKilled =
false
;
break
;
}
case
Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId,
true
);
if
(r.getLastStartId() == startId) {
// There is no more work, and this service
// doesn't want to hang around if killed.
r.stopIfKilled =
true
;
}
break
;
}
case
Service.START_REDELIVER_INTENT: {
// We'll keep this item until they explicitly
// call stop for it, but keep track of the fact
// that it was delivered.
ServiceRecord.StartItem si = r.findDeliveredStart(startId,
false
);
if
(si !=
null
) {
si.deliveryCount =
0
;
si.doneExecutingCount++;
// Don't stop if killed.
r.stopIfKilled =
true
;
}
break
;
}
case
Service.START_TASK_REMOVED_COMPLETE: {
// Special processing for onTaskRemoved(). Don't
// impact normal onStartCommand() processing.
r.findDeliveredStart(startId,
true
);
break
;
}
default
:
throw
new
IllegalArgumentException(
"Unknown service start result: "
+ res);
}
if
(res == Service.START_STICKY_COMPATIBILITY) {
r.callStart =
false
;
}
}
final
long
origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inStopping);
Binder.restoreCallingIdentity(origId);
}
else
{
Slog.w(TAG,
"Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private
void
serviceDoneExecutingLocked(ServiceRecord r,
boolean
inStopping) {
if
(DEBUG_SERVICE) Slog.v(TAG,
"<<< DONE EXECUTING "
+ r
+
": nesting="
+ r.executeNesting
+
", inStopping="
+ inStopping +
", app="
+ r.app);
else
if
(DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
"<<< DONE EXECUTING "
+ r.shortName);
r.executeNesting--;
if
(r.executeNesting <=
0
&& r.app !=
null
) {
if
(DEBUG_SERVICE) Slog.v(TAG,
"Nesting at 0 of "
+ r.shortName);
r.app.executingServices.remove(r);
if
(r.app.executingServices.size() ==
0
) {
if
(DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG,
"No more executingServices of "
+ r.shortName);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
if
(inStopping) {
if
(DEBUG_SERVICE) Slog.v(TAG,
"doneExecuting remove stopping "
+ r);
mStoppingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app);
}
}
|
01
02
03
04
|
public
int
onStartCommand(Intent intent,
int
flags,
int
startId) {
onStart(intent, startId);
return
mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
|
01
02
03
04
|
private
boolean
mStartCompatibility =
false
;
....
//省略若干无关方法与代码
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
|
因为一个运行服务的进程的优先级高于运行后台activity的进程,一个activity会准备一个长时间运行的操作来启动一个服务,而不是启动一个线程–尤其是这个操作可能会拖垮这个activity。例如后台播放音乐的同时,通过照相机向服务器发送一张照片,启动一个服务会保证这个操作至少运行在service 进程的优先级下,无论这个activity发生了什么,广播接收者应该作为一个空服务而不是简单的把耗时的操作单独放在一个线程里。
1、提升服务的优先级
Android AndroidManifest.xml 里面给服务增加优先级,通过content.StartService();方式启动服务。1000是最高值,如果数字越小则优先级越低
Intent intent = new Intent();
intent .setAction("com.xsl.push");
context.startService(intent );
2、在Android AndroidManifest.xml的application标签中添加android:persistent属性
android:icon="@drawable/app_default"
android:label="@string/app_name"
android:persistent="true" >
........................................
切记,这个不可滥用,系统中用这个的service,app一多,整个系统就完蛋了
3、在Service的onDestroy()中重启Service.这种方式,用户在无法再设置-运行的服务中将此服务停止
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Intent localIntent = new Intent();
localIntent.setClass(this, TestService.class); //销毁时重新启动Service
this.startService(localIntent);
}
===========================================================================
类别 | 区别 | 优点 | 缺点 | 应用 |
本地服务(Local) | 该服务依附在主进程上, | 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。 | 主进程被Kill后,服务便会终止。 | 非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。 |
远程服务(Remote) | 该服务是独立的进程, | 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 | 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。 | 一些提供系统服务的Service,这种Service是常驻的。 |
类别 | 区别 | 应用 |
前台服务 | 会在通知一栏显示 ONGOING 的 Notification, | 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification。 | 当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。 |
类别 | 区别 |
startService 启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService |
bindService 启动的服务 | 该方法启动的服务要进行通信。停止服务使用unbindService |
startService 同时也 bindService 启动的服务 | 停止服务应同时使用stepService与unbindService |
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 |
package com.newcj.test;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class LocalService1 extends Service {
/**
* onBind 是 Service 的虚方法,因此我们不得不实现它。
* 返回 null,表示客服端不能建立到此服务的连接。
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
|
1
2 3 4 5 |
// 启动一个 Activity
startActivity(new Intent(this, LocalService1.class));
...
// 停止一个 Activity
stopService(new Intent(this, LocalService1.class));
|
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 |
package com.newcj.test;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class LocalService extends Service {
/**
* 在 Local Service 中我们直接继承 Binder 而不是 IBinder,因为 Binder 实现了 IBinder 接口,这样我们可以少做很多工作。
* @author newcj
*/
public class SimpleBinder extends Binder{
/**
* 获取 Service 实例
* @return
*/
public LocalService getService(){
return LocalService.this;
}
public int add(int a, int b){
return a + b;
}
}
public SimpleBinder sBinder;
@Override
public void onCreate() {
super.onCreate();
// 创建 SimpleBinder
sBinder = new SimpleBinder();
}
@Override
public IBinder onBind(Intent intent) {
// 返回 SimpleBinder 对象
return sBinder;
}
}
|
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 |
package com.newcj.test;
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
public class Main extends Activity {
private final static String TAG = "SERVICE_TEST";
private ServiceConnection sc;
private boolean isBind;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sc = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;
Log.v(TAG, "3 + 5 = " + sBinder.add(3, 5));
Log.v(TAG, sBinder.getService().toString());
}
};
findViewById(R.id.btnBind).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
bindService(new Intent(Main.this, LocalService.class), sc, Context.BIND_AUTO_CREATE);
isBind = true;
}
});
findViewById(R.id.btnUnbind).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(isBind){
unbindService(sc);
isBind = false;
}
}
});
}
}
|
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 93 94 95 96 97 98 99 100 101 102 103 104 |
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);
}
}
|