Android服务总结

服务(Service)是一个在后台执行长时间操作而不提供用户界面的Android组件,由其他组件启动服务, 但是启动组件被销毁服务也不会被销毁. 服务因为其OOM优先级仅次于可见进程且被内存不足被回收后在内存回来的时候系统会再次开启被杀掉的服务, 其可靠性使一般处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互.

创建服务

AndroidManifest声明服务

1
2
<service android:name=".MyService" >
</service>

继承Service实现onBind()

1
2
3
4
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
}

开启和停止服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MainActivity extends AppCompatActivity {
private Intent mIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntent = new Intent(this, MyService.class); // 意图对象
}
public void startService(View view){
startService(mIntent); // 开启服务
}
public void stopService(View view) {
stopService(mIntent); //停止服务
}
}

如果服务的内部停止自身调用stopSelf()

绑定和解绑服务

直接开启的服务是独立的组件没有返回值或者回调方法. 服务执行的过程无法干涉和通信. 相当于你找一个女朋友帮你生猴子, 但是生的什么猴子, 什么时候生你都不能决定… 我觉得我不适合举例子. 直接说就是无法获取服务对象内的数据也无法调用内部的方法. 当然如果有人说创建一个服务对象调用方法不就行了吗? 但是这是一个新的对象(相当于又找了个女朋友), 开启服务和直接创建对象有区别的.

创建服务对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyService extends Service {
/**
* 可以在这里执行操作或者调用服务的方法
* 这里我之所以继承Binder而不继承IBind是因为IBind需要实现很多没必要的方法.
*/
class Handler extends Binder {
public void startDownload() {
// 开始下载
}
public void stopDownload() {
// 停止下载
}
}
/**
* @param intent bindService() 传递过来的参数
* @return
*/
@Override
public IBinder onBind(Intent intent) {
Log.i("日志", "MyService.onBind_13 >>> Bind");
return new Handler(); // 返回IBind的子类
}
}

在Activity当中绑定服务

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
public class MainActivity extends AppCompatActivity {
private Intent mIntent;
private MyService.Handler mService;
// 创建匿名内部类对象
private ServiceConnection mConnection = new ServiceConnection() {
/**
* 在绑定服务的时候回调
* @param name 绑定服务的组件名对象
* @param service onBind()方法返回的对象
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = (MyService.Handler) service; // 这样就能
}
/**
* 该方法在意外终止服务的情况下回调, 例如服务奔溃. 取消绑定服务并不会调用
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntent = new Intent(this, MyService.class);
}
public void bindService(View view) {
bindService(mIntent, mConnection, BIND_AUTO_CREATE); // 绑定服务
}
public void unbindService(View view) {
unbindService(mConnection); // 解绑服务
}
}

生命周期

方法 描述
onCreate() 创建服务时执行. 服务只能创建一次
onStartCommand() 开启服务时执行. 服务可以开启多次
onBind() 绑定服务时执行. 服务只能绑定一次
onUbind() 解绑服务时执行. 服务只能解绑一次, 否则抛出异常
onRebind() 当新的客户端与服务连接,且此前它已经通过onUnbind()通知断开连接时执行
onDestroy() 服务销毁时执行.

开启服务的生命周期

绑定服务的生命周期

注意

  • 关于onDestroy()是否执行
    1. 如果服务未解绑的情况下stopService()不会销毁服务
    2. 如果是开启服务的情况下又绑定服务, unbindService()不会销毁服务
  • 即使解绑后再绑定也不会执行onBind()onUnbind(), 除非销毁服务.
  • 绑定服务不会开启一个服务在后台运行, 只是会在堆内存中创建一个对象.

进程优先级

进程的内存管理优先级分为五种, 按照从高到低顺序

  1. 前台进程: 当前用户正在操作的界面(onResume())
  2. 可见进程: 失去焦点(onPause())的不可操作界面, 但是用户可见
  3. 服务进程: 有服务组件正在运行的
  4. 后台进程: 后台执行中(onStop()), 内存告急时回收
  5. 空闲进程: 没有任何活动组件在运行(onDestroy()), 非常容易被内存回收

服务正是因为其优先级非常高所以被常常用来网络数据下载同步或者IO数据读写操作. 服务还有一个特性那就是内存告急时回收, 但是如果内存充足的情况下又会自动启动.

前台服务

360p

IntentService

由于服务一般都是处理耗时操作(下载, 数据同步..)在子线程运行, 而一般服务都是在主线程运行需要自己开启子线程, 略显麻烦. 所以Google为我们提供了一个特殊的服务类IntentService自动开启工作线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SubThreadService extends IntentService {
/**
* 由于父类没有空参构造方法所以需要访问父类有参
*/
public SubThreadService() {
super("开的子线程名字, 随便取");
}
/**
* 注意只有这个方法是在子线程运行的, 并不是说整个服务的所有方法都在子线程
*
* @param intent 开启服务传的意图对象
*/
@Override
protected void onHandleIntent(Intent intent) {
// 如果这个方法执行完会自动销毁服务
}
}

清单文件同样要声明服务, 其他和一般服务一样使用.

远程服务

远程服务其实就是开启一个新的进程, 进程都不一样了当然也不在其程序的主线程了. 所以耗时操作没任何问题. 拥有独立进程的服务不受主进程影响, 并且由于不提供界面所以在最近任务管理器中不会显示, 所以自然也不会被用户杀掉.

1
2
3
4
5
6
<service
android:name=".MyService"
android:process=":remote"
android:enabled="true"
android:exported="true">
</service>
  • process: 这是进程名, :开头前面会跟应用ID名. 遵照应用ID规则命名, 你写成com.google.service也是没问题的.
  • enabled: 决定是否能被实例化, 如果是false服务无法被创建
  • exported: 决定是否能被其他进程访问或者开启

新建进程开启服务也有面临一个问题, 无法绑定服务. 在Android中默认进程间是无法通讯的, 这个时候就需要用到

AIDL

AIDL(Android Interface Definition Language)是Android接口定义语言的意思,是Google为我们封装的IDL语言, 它可以用于让某个Service与多个应用程序组件之间进行跨进程通信(IPC),从而可以实现多个应用程序共享同一个Service的功能, 当然不局限于Service其他组件也可以.