如果一个Service在某个Activity中被调用bindService方法启动,不论bindService被调用几次,Service的onCreate方法只会执行一次,同时onStartCommand方法始终不会调用。
当建立连接后,Service会一直运行,除非调用unbindService来接触绑定、断开连接或调用该Service的Context不存在了(如Activity被Finish——即通过bindService启动的Service的生命周期依附于启动它的Context),系统在这时会自动停止该Service。
注意点:
第一次 bindService 会触发 onCreate 和 onBind,以后在服务运行过程中,每次 bindService 都不会触发任何回调
3.混合型(上面两种方式的交互)
当一个Service在被启动(startService)的同时又被绑定(bindService),该Service将会一直在后台运行,并且不管调用几次,onCreate方法始终只会调用一次,onStartCommand的调用次数与startService调用的次数一致(使用bindService方法不会调用onStartCommand)。同时,调用unBindService将不会停止Service,必须调用stopService或Service自身的stopSelf来停止服务。
在什么情况下使用 startService 或 bindService 或 同时使用startService 和 bindService?
①如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。
②如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。
③如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。
四、Service的几种典型使用实例
1.不可交互的后台服务
不可交互的后台服务即是普通的Service,通过startService()方式开启。Service的生命周期很简单,分别为onCreate、onStartCommand、onDestroy这三个。
创建服务类:
public class BackService extends Service {
private Thread mThread;
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println(“onBind”);
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//执行耗时操作
mThread = new Thread() {
@Override
public void run() {
try {
while (true) {
//等待停止线程
if (this.isInterrupted()) {
throw new InterruptedException();
}
//耗时操作。
System.out.println(“执行耗时操作”);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mThread.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
//停止线程
mThread.interrupt();
}
}
配置服务:
如果想配置成远程服务,加如下代码:
android:process=“remote”
配置好Service类,只需要在前台,调用startService()方法,就会启动耗时操作。
注意:
①不运行在一个独立的进程中,它同样执行在UI线程中,因此,在Service中创建了子线程来完成耗时操作。
②当Service关闭后,如果在onDestory()方法中不关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的,此时关闭该子线程的方法需要直接关闭该应用程序。因此,在onDestory()方法中要进行必要的清理工作。
2.可交互的后台服务
可交互的后台服务是指前台页面可以调用后台服务的方法,通过bindService()方式开启。Service的生命周期很简单,分别为onCreate、onBind、onUnBind、onDestroy这四个。
可交互的后台服务实现步骤是和不可交互的后台服务实现步骤是一样的,区别在于启动的方式和获得Service的代理对象。
创建服务类
和普通Service不同在于这里返回一个代理对象,返回给前台进行获取,即前台可以获取该代理对象执行后台服务的方法
public class BackService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回MyBinder对象
return new MyBinder();
}
//需要返回给前台的Binder类
class MyBinder extends Binder {
public void showTip(){
System.out.println(“我是来此服务的提示”);
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
前台调用
通过以下方式绑定服务:
bindService(mIntent,con,BIND_AUTO_CREATE);
其中第二个参数:
private ServiceConnection con = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
BackService.MyBinder myBinder = (BackService.MyBinder) service;
myBinder.showTip();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
当建立绑定后,onServiceConnected中的service便是Service类中onBind的返回值。如此便可以调用后台服务类的方法,实现交互。
当调用unbindService()停止服务,同时要在onDestory()方法中做好清理工作。
注意:通过bindService启动的Service的生命周期依附于启动它的Context。因此当前台调用bindService的Context销毁后,那么服务会自动停止。
3.混合型后台服务
将上面两种启动方式结合起来就是混合性交互的后台服务了,即可以单独运行后台服务,也可以运行后台服务中提供的方法,其完整的生命周期是:onCreate->onStartCommand->onBind->onUnBind->onDestroy
4.前台服务
所谓前台服务只不是通过一定的方式将服务所在的进程级别提升了。前台服务会一直有一个正在运行的图标在系统的状态栏显示,非常类似于通知的效果。
由于后台服务优先级相对比较低,当系统出现内存不足的情况下,它就有可能会被回收掉,所以前台服务就是来弥补这个缺点的,它可以一直保持运行状态而不被系统回收。
创建服务类
前台服务创建很简单,其实就在Service的基础上创建一个Notification,然后使用Service的startForeground()方法即可启动为前台服务。
public class ForeService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
beginForeService();
}
private void beginForeService() {
//创建通知
Notification.Builder mBuilder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText(“2017-2-27”)
.setContentText(“您有一条未读短信…”);
//创建点跳转的Intent(这个跳转是跳转到通知详情页)
Intent intent = new Intent(this,NotificationShow.class);
//创建通知详情页的栈
TaskStackBuilder stackBulider = TaskStackBuilder.create(this);
//为其添加父栈 当从通知详情页回退时,将退到添加的父栈中
stackBulider.addParentStack(NotificationShow.class);
PendingIntent pendingIntent = stackBulider.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
//设置跳转Intent到通知中
mBuilder.setContentIntent(pendingIntent);
//获取通知服务
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//构建通知
Notification notification = mBuilder.build();
//显示通知
nm.notify(0,notification);
//启动前台服务
startForeground(0,notification);
}
}
启动前台服务
startService(new Intent(this, ForeService.class));
关于TaskStackBuilder 这一段,可能不是看的很明白,下面详细介绍。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/c9af3cee90e244863dfc580fe8802757.jpeg)
总结
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
(img-VtDYIA5K-1712684215394)]
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!