Service在程序的后台运行
Service
Service是Context的子类
UI控件是线程不安全的,所有的UI操作必须在主线程中
Service并不会自动开启线程,所有代码默认运行在主线程,要手动开启子线程
在服务里开的子线程(IntentService)比在活动里开的子线程(AsyncTask)重要性更高更不容易被杀死
Service的使用
右击New→Service→Service
Export
属性表示是否允许其它程序访问这个Service
Enabled
属性表示是否启用这个Service
在任何一个位置都可以调用stopSelf()
方法使Service
停止
普通使用
启动Service
Intent intent=new Intent(this,MyService.class);
startService(intent);
结束Service
Intent intent=new Intent(this,MyService.class);
stopService(intent);
与Activity绑定
public class MyService extends Service {
class MyBinder extends Binder{
public void startSomething(){
...//可以在这里开IntentService
}
}
public MyService() { }
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();//把连接器暴露给外部,活动就可以使用连接器里的方法,在Service中执行
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
在活动中使用ServiceConnection获得Service返回回来的连接器
实现了指挥服务去干什么服务就去干什么的功能
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder myBinder=(MyService.MyBinder) service;//获得连接器
myBinder.startSomething();//执行连接器中的方法
}
@Override
public void onServiceDisconnected(ComponentName name) { }
};
启动绑定
Intent intent=new Intent(this,MyService.class);
bindService(intent,connection,BIND_AUTO_CREATE);//通过ServiceConnection与后台某项特定服务绑定
结束绑定
unbindService(connection);
Service的生命周期
若进程里的Service正在执行生命周期回调,那么这个进程属于前台进程
若进程里的Service与目前处于前台的活动绑定,那么这个进程属于前台进程
使用startService()方式启动
只有第1次启动执行onCreate()
->每次启动都执行onStartCommand()
->stopService()/自己stopSelf()则执行onDestroy()
-
适用于长期执行进行某项任务
-
不管是否有Activity使用bindService()/unbindService()到该Service,该Service一直在后台运行,直到被调用stopService()/自己stopSelf()
-
不管startService()多少次,stopService()1次就会停止服务
-
Service启动之后就和Activity没什么关联了,不要求在Activity退出时手动退出Service
使用bindService()方式启动
只有第1次启动执行onCreate()
->只有第1次启动执行onBind()
->unbindService()则执行onUnBind()
->onDestroy()
-
适用于与正在运行的Service取得联系/类似懒汉式的思路,开始先不创建,在需要用到的时候去bind一下,节约资源
-
该Service一直在后台运行,直到被调用unbindService()解绑/绑定了该Service的Context不存在了
-
Service生命周期依附于启动它的Context,因此当前台调用bindService()的Context销毁
后
,Service也会自动调用onUnbind()和onDestory()
使用混合型方式启动
Service被startService()的同时又被bindService(),该Service将会一直在后台运行,并且不管调用几次,onCreate()方法始终只会调用一次,onStartCommand()的调用次数与startService()调用的次数一致(使用bindService()方法不会调用onStartCommand())。同时,调用unBindService()将不会停止Service,必须调用stopService()或Service自身的stopSelf()来停止服务
前台Service
8.0+Service运行在后台时随时会被系统回收,只有应用前台可见时(以类似通知的形式存在),Service才能稳定运行
渠道一旦建立,修改渠道属性将不再生效,除非卸载重装/更改渠道id
9.0+需要添加一条普通权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
在Service的onCreate()方法
@Override
public void onCreate() {
super.onCreate();
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("foreground", "前台Service", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
Intent intent = new Intent(this, MainActivity.class);
//这里也可以使用taskStackBuilder的方式获得pendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
//使用compat可以兼容所有安卓版本,参数为(上下文,渠道id)
Notification notification= new NotificationCompat.Builder(this,"foreground")
.setContentTitle("通知标题")
.setContentText("通知内容")
.setSmallIcon(R.drawable.xxx)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.xxx))//将图片解析为Bitmap
.setShowWhen(false)//是否显示时间
.setNotificationSilent()//静默通知
.setVisibility(NotificationCompat.VISIBILITY_SECRET)//锁屏不可见
.setContentIntent(pending)//点击通知后跳转到的页面
.build();//创建通知对象
//注意启动通知的方式不是通过管理器发送通知,而是启动前台
startForeground(1, notification);
}
取消
-
将前台服务降为后台服务,可以让它从任务栏消失
//此时服务并没有停止,直到调用stopService()
stopForeground(true);
-
直接stopService(),无论Service在前/后台都会直接结束啦
IntentService
是Service的子类
Service
本身是在主线程中运行,如果执行耗时操作需要自己手动开启子线程并且在运行结束后调用stopSelf
或者stopService
来停止,这样可行,但是自己去管理Service
的生命周期和子线程并不是一个好的选择,因此android提供了IntentService
来实现自动开启子线程并关闭
新建一个继承了IntentService的类
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//这个方法已经是在子线程中运行的了,可以处理一些耗时逻辑
}
}
使用方法
Intent intent=new Intent(this,MyIntentService.class);
startService(intent);
既然是Service就要在Manifest文件里注册
<service
android:name=".MyIntentService"
android:enabled="true"
android:exported="true" />