文章目录
一、Service简介
Service是Android程序中的四大组件之一,他和Activity一样都是Context的子类,只不过他没有UI界面,是在后台运行的组件。
二、Service种类
按运行地点分类
类别 | 区别 | 优点 | 缺点 | 应用 |
---|---|---|---|---|
本地服务(Local Service) | 该服务依附在主进程上 | 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。 | 主进程被Kill后,服务便会终止。 | 例如:音乐播放器等不需要常驻的服务 |
远程服务(Remote Service) | 该服务是独立的进程 | 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process 字符串。由于是独立的进程,因此Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。 | 该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC。 | 一些提供系统服务的Service 这种 Service是常驻的。 |
按运行类型分类
类别 | 区别 | 应用 |
---|---|---|
前台服务 | 会在通知栏显示onGoing的Notification | 当服务被终止的时候,通知一栏的Notification 也会消失,这样对于用户有一定的通知作用。常见的如 "音乐播放服务" |
后台服务 | 默认的服务即为后台服务,即不会在通知栏显示 onGoing 的Notification | 当服务被终止的时候,用户是看不到效果的,某些不需要运行或终止提示的服务,"如天气更新,日期同步,邮件同步等" |
按使用方式分类
类别 | 区别 |
---|---|
startService启动的服务 | 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService |
bindService启动的服务 | 方法启动的服务要进行通信。停止服务使用 unbindService。 |
同时使用startService、bindService启动的服务 | 停止服务应同时使用stopService与 unbindService。 |
三、Service生命周期
onCreate: 系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果service已经运行,这个方法不会被调用。
onStartCommand: 每次客户端调用startService 方法启动该Service都会回调该方法。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf 或 topService来停止服务。
onBind: 当组件调用 bindService 想要绑定到service时 (例如想要执行进程间通讯) 系统调用此方法 (一次调用,一旦绑定后,下次再调用bindService不会回调该方法) 在你的实现中,你必须提供一个返回一个IBinder 来以使客户端能够使用它与service 通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回 NULL
onUnbind: 当前组件调用 unbindService,想要解除与service 的绑定时系统调用此方法 (一次调用,一旦解除绑定后,下次再调用unbindService会抛出异常)
onDestory: 系统在service 不再被使用并要销毁时调用此方法 (一次调用)。service 应在此方法中释放资源, 例如 线程,已注册的侦听器,接收器等等。这是service收到的最后一个调用。
1.startService/stopService
生命周期:
注意点:
- 第一次 startService 会触发onCreate 和 onStartCommand,以后在服务运行过程中,每次startService都只会触发onStartCommand
- 不论startService多少次,stopService一次就会停止服务
2.bindService/unbindService
生命周期:
注意点:
第一次bindService会触发 onCreate、onBind,以后在服务运行过程中,每次调用bindService都不会触发任何回调。
3. 混合型(上面两种方式的交互)
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG,"onServiceConnected"+service.toString());
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG,"onServiceDisconnected"+name);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_life_cycle);
Intent intent = new Intent(this,BaseService.class);
startService(intent);
bindService(intent,connection,BIND_AUTO_CREATE);
((Button) findViewById(R.id.btn_next)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);
}
});
((Button) findViewById(R.id.btn_back)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);
}
});
}
public class BaseService extends Service {
public static final String TAG = "BaseService";
private MyBinder myBinder;
@Override
public void onCreate() {
super.onCreate();
myBinder = new MyBinder();
Log.i(TAG, "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return myBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) {
}
}
}
生命周期:
执行stopService时无效
执行 "unbindService(connection)"
4.前台服务
所谓前台服务只不过通过一定的方式将服务所在的进程级别提升了。前台服务会一直有一个正在运行的图标再系统的状态栏显示。非常类似与通知效果。
Service 的 startForegroud 方法可启动为前台服务。
执行 startForegroud 方法时需要添加权限 <uses-permissionandroid:name=“android.permission.FOREGROUND_SERVICE”/>
intent = new Intent(this, ForeService.class);
startService(intent);
public class ForeService extends Service {
private static final String childID = "channel_1";
private static final String childName = "channel";
private static final String description = "这个市描述Description";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
beginForeService();
}
private void beginForeService() {
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importanceHigh = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(childID,childName,importanceHigh);
channel.setDescription(description);
channel.enableLights(true);
channel.setLightColor(Color.BLUE);
channel.enableVibration(true);//是否震动
channel.setVibrationPattern(new long[]{100,200,300,400,500,400,300,200,400});
channel.setShowBadge(true);
manager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,childID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("标题")
.setContentText("内容");
Intent intent = new Intent(this,TwoLifeCycleActivity.class);
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
taskStackBuilder.addParentStack(TwoLifeCycleActivity.class);
taskStackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = taskStackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(pendingIntent);
manager.notify(1,builder.build());
startForeground(1,builder.build());
}
}
使用PendingIntent来跳转到 TwoLifeCycleActivity。
这句话的意思是:为跳转后的activity添加一个父activity,在activity中manifest中添加parentActivityName即可
<activity
android:name=".TwoLifeCycleActivity"
android:parentActivityName=".LifeCycleActivity"/>
parentActivity为LifeCycleActivity,也就是说在TwoLifeCycleActivity这个界面点击回退时,会跳转到MainActivity这个界面,而不是像上面一样直接回到home菜单。
stopForeground 方法可以取消通知,将前台服务降至后台服务。
此时服务依然存在没有停止,
stopService可以把前台服务停止