序言

最近项目要实现这样一个效果:运行后,要有一个service始终保持在后台运行,不管用户作出什么操作,都要保证service不被kill。参考了现今各种定制版的系统和安全厂商牛虻软件,如何能保证自己的Service不被杀死呢?其实除了常规的手段,我们可以参考一下 微信 和360,设置-程序-正在运行,可以看到微信是同时开启了两个进程和服务:

Service简介

Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过来声明。可以通过contect.startservice和contect.bindserverice来启动。和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现(或者用系统提供的IntentService,它继承了Service,它处理数据是用自身新开的线程)。【 当然你也可以在新的线程中startService,这样Service就不是在MainThread了 】

本地服务  Local Service 用于应用程序内部

它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。

【用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好】

远程服务  Remote Service 用于 Android 系统内部的应用程序之间

它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。

【可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可】

1,Service的生命周期

2,Service运行方式

以startService()启动服务,系统将通过传入的Intent在底层搜索相关符合Intent里面信息的service。如果服务没有启动则先运行onCreate,然后运行onStartCommand (可在里面处理启动时传过来的Intent和其他参数),直到明显调用stopService或者stopSelf才将停止Service。无论运行startService多少次,只要调用一次stopService或者stopSelf,Service都会停止。使用stopSelf(int)方法可以保证在处理好intent后再停止。onStartCommand ,在2.0后被引入用于service的启动函数,2.0之前为public void onStart(Intent intent, int startId) 。

以bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。

3,拥有service的进程具有较高的优先级

官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。

1. 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。

2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.

3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。

4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。

5. 如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。

实现前台:

Service如果要防止尽可能不被系统杀掉,需要设置为在前台运行。

1.MainActivity.java
1
package
com.example.helloteacher;
2
3
import
com.example.teacherService.HelloteacherService;
4
import
com.example.teacherService.HelloteacherService2;
5
6
import
android.app.Activity;
7
import
android.content.Intent;
8
import
android.os.Bundle;
9
import
android.util.Log;
10
import
android.view.View;
11
import
android.widget.Button;
12
import
android.widget.TextView;
13
14
public
class
MainActivity
extends
Activity {
15
private
TextView fuction;
16
private
Button start;
17
@Override
18
protected
void
onCreate(Bundle savedInstanceState) {
19
super
.onCreate(savedInstanceState);
20
setContentView(R.layout.activity_main);
21
//
初始化控件
22
init();
23
//
创建进程
24
inProcess();
25
}
26
//
/初始化控件函数
27
private
void
init() {
28
start=
(Button)findViewById(R.id.button1);
29
fuction=
(TextView)findViewById(R.id.tv_bottom_funtion);
30
start.setOnClickListener(
new
StartOnClickListener());
31
fuction.setOnClickListener(
new
FuctionOnClickListener());
32
}
33
//
功能按钮监听实现函数
34
private
final
class
FuctionOnClickListener
implements
View.OnClickListener{
35
36
@Override
37
public
void
onClick(View v) {
38
//
TODO Auto-generated method stub
39
Intent intent =
new
Intent(MainActivity.
this
, FuctionActivity.
class
);
40
startActivity(intent);
41
}
42
}
43
//
进程函数
44
private
void
inProcess(){
45
Intent intent =
new
Intent(MainActivity.
this
, HelloteacherService.
class
);
46
startService(intent);
47
Intent intent2 =
new
Intent(MainActivity.
this
, HelloteacherService2.
class
);
48
startService(intent2);
49
}
50
private
final
class
StartOnClickListener
implements
View.OnClickListener{
51
52
@Override
53
public
void
onClick(View v) {
54
55
}
56
}
57
58
59
}
2.HelloteacherService.java
1
package
com.example.teacherService;
2
3
import
com.example.Receiver.Alarmreceiver;
4
import
com.example.helloteacher.R;
5
6
import
android.app.AlarmManager;
7
import
android.app.Notification;
8
import
android.app.PendingIntent;
9
import
android.app.Service;
10
import
android.content.Intent;
11
import
android.os.IBinder;
12
import
android.os.SystemClock;
13
import
android.util.Log;
14
15
public
class
HelloteacherService
extends
Service {
16
HelloteacherService2 hs2;
17
private
String TAG="HelloteacherService"
;
18
@Override
19
public
void
onCreate() {
20
super
.onCreate();
21
Log.i(TAG, "-->>onCreate"
);
22
}
23
24
@Override
25
public
int
onStartCommand(Intent intent,
int
flags,
int
startId) {
26
Log.i(TAG, "-->>onStartCommand-->>"+
startId);
27
flags =
START_STICKY;
28
29
//
启用前台服务,主要是startForeground()
30
Notification notification =
new
Notification(R.drawable.ic_launcher, "用电脑时间过长了!白痴!"
31
, System.currentTimeMillis());
32
notification.setLatestEventInfo(
this
, "快去休息!!!"
,
33
"一定保护眼睛,不然遗传给孩子,老婆跟别人跑啊。",
null
);
34
//
设置通知默认效果
35
notification.flags =
Notification.FLAG_SHOW_LIGHTS;
36
startForeground(1
, notification);
37
38
AlarmManager manager =
(AlarmManager) getSystemService(ALARM_SERVICE);
39
//
读者可以修改此处的Minutes从而改变提醒间隔时间
40
//
此处是设置每隔55分钟启动一次
41
//
这是55分钟的毫秒数
42
int
Minutes = 55 * 60 * 1000
;
43
//
SystemClock.elapsedRealtime()表示1970年1月1日0点至今所经历的时间
44
long
triggerAtTime = SystemClock.elapsedRealtime() +
Minutes;
45
//
此处设置开启AlarmReceiver这个Service
46
Intent i =
new
Intent(
this
, Alarmreceiver.
class
);
47
PendingIntent pi = PendingIntent.getBroadcast(
this
, 0, i, 0
);
48
//
ELAPSED_REALTIME_WAKEUP表示让定时任务的出发时间从系统开机算起,并且会唤醒CPU。
49
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
50
51
return
super
.onStartCommand(intent, flags, startId);
52
}
53
//
监听服务2实现函数
54
55
56
@Override
57
public
IBinder onBind(Intent arg0) {
58
Log.i(TAG, "-->>onBind"
);
59
//
TODO Auto-generated method stub
60
return
null
;
61
}
62
@Override
63
public
void
onDestroy() {
64
Log.i(TAG, "-->>onDestroy"
);
65
super
.onDestroy();
66
67
}
68
}
3.BootReceiver.java
1
package
com.example.Receiver;
2
3
import
android.app.AlarmManager;
4
import
android.app.PendingIntent;
5
import
android.content.BroadcastReceiver;
6
import
android.content.Context;
7
import
android.content.Intent;
8
import
android.os.SystemClock;
9
10
public
class
BootReceiver
extends
BroadcastReceiver {
11
12
/*
要接收的intent源
*/
13
static
final
String ACTION = "android.intent.action.BOOT_COMPLETED"
;
14
15
public
void
onReceive(Context context, Intent mintent)
16
{
17
if
(Intent.ACTION_BOOT_COMPLETED.equals(mintent.getAction())) {
18
//
启动完成
19
Intent intent =
new
Intent(context, Alarmreceiver.
class
);
20
intent.setAction("arui.alarm.action"
);
21
PendingIntent sender = PendingIntent.getBroadcast(context, 0
,
22
intent, 0
);
23
long
firstime =
SystemClock.elapsedRealtime();
24
AlarmManager am =
(AlarmManager) context
25
.getSystemService(Context.ALARM_SERVICE);
26
27
//
10秒一个周期,不停的发送广播
28
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstime,
29
10 * 1000
, sender);
30
}
31
}
32
33
34
}
4.Alarmreceiver.java
1
package
com.example.Receiver;
2
3
import
com.example.teacherService.HelloteacherService;
4
5
import
android.content.BroadcastReceiver;
6
import
android.content.Context;
7
import
android.content.Intent;
8
9
public
class
Alarmreceiver
extends
BroadcastReceiver {
10
11
@Override
12
public
void
onReceive(Context context, Intent intent) {
13
//
TODO Auto-generated method stub
14
if
(intent.getAction().equals("arui.alarm.action"
)) {
15
Intent i =
new
Intent();
16
i.setClass(context, HelloteacherService.
class
);
17
//
启动service
18
//
多次调用startService并不会启动多个service 而是会多次调用onStart
19
context.startService(i);
20
}
21
}
22
23
}
5.配置文件
AndroidManifest.xml
下面是添加在配置文件中的部分代码:
1
<
activity
android:name
="com.example.helloteacher.FuctionActivity"
/>
2
<
service
android:name
="com.example.teacherService.HelloteacherService"
android:process
=":HelloteacherService"
/>
3
<
service
android:name
="com.example.teacherService.HelloteacherService2"
/>
4
<
uses-permission
android:name
="android.permission.RECEIVE_BOOT_COMPLETED"
>
uses-permission
>
5
<
receiver
android:name
="com.example.Receiver.BootReceiver"
>
6
<
intent-filter
>
7
<
action
android:name
="android.intent.action.BOOT_COMPLETED"
/>
8
intent-filter
>
9
receiver
>
10
<
receiver
android:name
="com.example.Receiver.Alarmreceiver"
>
11
<
intent-filter
>
12
<
action
android:name
="arui.alarm.action"
/>
13
intent-filter
>
14
receiver
>

通过以上的配置,就可以实现Service的前台运行!下面附上效果图: