你将获得以下知识:
- 基本概念
- 生命周期
- 与Thread区别
- IntentService
- 与Activity区别
- 使用
一、Service 是什么
1.1 什么是 Service
-
Service(服务) 是一种可以在后台长时间执行操作而没有用户界面的应用组件。 -
服务可由其他应用组件启动(如
Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响(start方式)。 -
组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (
IPC)。
1.2 Service 通常总是称为 “后台服务”
- 其中 “后台” 一词是相对于前台而言的,具体是指:其本身的运行并不依赖于用户可视的
UI界面 - 因此,从实际业务需求上来理解,
Service的适用场景应该具备以下条件:
- 并不依赖于用户可视的
UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的) - 具有较长时间的运行、运行在主线程当中的特性
1.3 服务进程
- 服务进程是通过
startService()方法启动的进程,但不属于前台进程和可见进程。例如,在后台播放音乐或者在后台下载就是服务进程。 - 系统保持它们运行,除非没有足够内存来保证所有的前台进程和可视进程。
二篇、生命周期
2.1 Service 的生命周期
- 我们先来看看
Service的生命周期 的基本流程
2.2 开启 Service 的两种方式
2.2.1 startService()
-
定义一个类继承
Service -
在
Manifest.xml文件中配置该Service -
使用
Context的startService(intent)方法开启服务。 -
使用
Context的stopService(intent)方法关闭服务。 -
该启动方式,
app杀死、Activity销毁没有任何影响,服务不会停止销毁。
2.2.2 bindService()
- 创建
BindService服务端,继承Service并在类中,创建一个实现IBinder接口的实例对象,并提供公共方法给客户端(Activity)调用。 - 从
onBinder()回调方法返回该Binder实例。 - 在客户端(
Activity)中, 从onServiceConnection()回调方法参数中接收Binder,通过Binder对象即可访问Service内部的数据。 - 在
manifests中注册BindService, 在客户端中调用bindService()方法开启绑定Service, 调用unbindService()方法注销解绑Service。 - 该启动方式依赖于客户端生命周期,当客户端
Activity销毁时, 没有调用unbindService()方法 ,Service也会停止销毁。
2.3 Service 有哪些启动方法,有什么区别,怎样停用 Service
-
在
Service的生命周期中,被回调的方法比Activity少一些,只有onCreate,onStart,onDestroy,onBind和onUnbind。 -
通常有两种方式启动一个
Service, 他们对Service生命周期的影响是不一样的。
2.3.1 通过 startService
Service会经历onCreate到onStart,然后处于运行状态,stopService的时候调用onDestroy方法。
2.3.2 通过 bindService
Service 会运行 onCreate ,然后是调用 onBind , 这个时候调用者和 Service 绑定在一起。调用者退出了,Srevice 就会调用 onUnbind -> onDestroyed 方法。
2.3.3 需要注意的是如果这几个方法交织在一起的话,会出现什么情况呢?
-
一个原则是
Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又bindService,Service只被创建一次。 -
如果先是
bind了,那么start的时候就直接运行Service的onStart方法,如果先是start,那么bind的时候就直接运行onBind方法。 -
如果
service运行期间调用了bindService,这时候再调用stopService的话,service是不会调用onDestroy方法的,service就stop不掉了,只能调用UnbindService,service就会被销毁 -
如果一个
service通过startService被start之后,多次调用startService的话,service会多次调 用onStart方法。多次调用stopService的话,service只会调用一次onDestroyed方法。 -
如果一个
service通过bindService被start之后,多次调用bindService的话,service只会调用一次onBind方法。多次调用unbindService的话会抛出异常。
第三篇:Service 与 Thread
3.1 Service 和 Thread 的区别
-
thread是程序执行的最小单元,他是分配cpu的基本单位安卓系统中,我们常说的主线程,UI线程,也是线程的一种。当然,线程里面还可以执行一些耗时的异步操作。 -
而
service大家记住,它是安卓中的一种特殊机制,service是运行在主线程当中的,所以说它不能做耗时操作,它是由系统进程托管,其实service也是一种轻量级的IPC通信,因为activity可以和service绑定,可以和service进行数据通信。 -
而且有一种情况,
activity和service是处于不同的进程当中,所以说它们之间的数据通信,要通过IPC进程间通信的机制来进行操作。
3.1.2 第二点是在实际开发的过程当中
-
在安卓系统当中,线程一般指的是工作线程,就是后台线程,做一些耗时操作的线程,而主线程是一种特殊的线程,它只是负责处理一些
UI线程的绘制,UI线程里面绝对不能做耗时操作,这里是最基本最重要的一点。(这是Thread在实际开发过程当中的应用) -
而
service是安卓当中,四大组件之一,一般情况下也是运行在主线程当中,因此service也是不可以做耗时操作的,否则系统会报 ANR 异常(ANR全称:Application Not Responding),就是程序无法做出响应。 -
如果一定要在
service里面进行耗时操作,一定要记得开启单独的线程去做。
3.1.3 第三点是应用场景上
-
当你需要执行耗时的网络,或者这种文件数据的查询,以及其它阻塞
UI线程的时候,都应该使用工作线程,也就是开启一个子线程的方式。 -
这样才能保证
UI线程不被占用,而影响用户体验。 -
而
service来说,我们经常需要长时间在后台运行,而且不需要进行交互的情况下才会使用到服务,比如说,我们在后台播放音乐,开启天气预报的统计,还有一些数据的统计等等。
3.2 为什么要用 Service 而不是 Thread
-
Thread的运行是独立于Activity的,也就是当一个Activity被finish之后,如果没有主动停止Thread或者Thread中的run没有执行完毕时那么这个线程会一直执行下去。 -
因此这里会出现一个问题:当
Activity被finish之后,你不再持有该Thread的引用。 -
另一方面,你没有办法在不同的
Activity中对同一Thread进行控制。
3.3 Service 里面是否能执行耗时的操作
- service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )
Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作(比如:网络请求,拷贝数据库,大文件),否则会引起ANR。- 如果想在服务中执行耗时的任务。有以下解决方案:
-
在
service中开启一个子线程 -
可以使用
IntentService异步管理服务
3.4 Service 是否在 main thread 中执行
-
默认情况, 如果没有显示的指
service所运行的进程,Service和activity是运 行在当前app所在进程的main thread(UI主线程)里面。 -
Service和Activity在同一个线程,对于同一app来说默认情况下是在同一个线程中的main Thread(UI Thread) -
特殊情况 ,可以在清单文件配置
service执行所在的进程 ,让service在另 外的进程中执行Service不死之身
3.4.1 在 onStartCommand 方法中将 flag 设置为 START_STICKY ;
3.4.2 在 xml 中设置了 android:priority
<!--设置服务的优先级为MAX_VALUE-->
<service android:name=".MyService"
android:priority="2147483647"
>
</service>
3.4.3 在 onStartCommand 方法中设置为前台进程
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification(R.mipmap.ic_launcher, "服务正在运行",System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent,0);
RemoteViews remoteView = new RemoteViews(this.getPackageName(),R.layout.notification);
remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
remoteView.setTextViewText(R.id.text , "Hello,this message is in a custom expanded view");
notification.contentView = remoteView;
notification.contentIntent = pendingIntent;
startForeground(1, notification);
return Service.START_STICKY;
}
第四篇:IntentService
4.1 什么是 IntentService
IntentService是Service的子类,比普通的Service增加了额外的功能。- 我们常用的
Service存在两个问题:
Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务
4.2 IntentService 的特征
-
会创建独立的
worker线程来处理所有的Intent请求 -
会创建独立的
worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题 -
所有请求处理完成后,
IntentService会自动停止,无需调用stopSelf()方法停止Service -
为
Service的onBind()提供默认实现,返回null -
为
Service的onStartCommand提供默认实现,将请求Intent添加到队列中
4.3 Service 和 IntentService 区别
4.3.1 Service 是用于后台服务的
-
当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了
Service这个概念 -
那么这里面要强调的是:
Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
4.3.2 当我们编写的耗时逻辑,不得不被 service 来管理的时候,就需要引入 IntentService 。
-
IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期。 -
那么与
service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。
4.3.3 使用:
重写 protected abstract void onHandleIntent(Intent intent)
4.3.4 IntentService 可以处理异步请求的 Service
-
使用时你只需要继承
IntentService和重写其中的onHandleIntent(Intent)方法接收一个Intent对象 , 在适当的时候会停止自己 ( 一般在工作完成的时候 ) 。 -
所有的请求的处理都在一个工作线程中完成 , 它们会交替执行 ( 但不会阻塞主线程的执行 ) ,一次只能执行一个请求。
4.3.5 是一个基于消息的服务
-
每次启动该服务并不是马上处理你的工作,而是首先会创建对应的
Looper,Handler并且在MessageQueue中添加的附带客户Intent的Message对象。 -
当
Looper发现有Message的时候接着得到Intent对象通过在onHandleIntent((Intent)msg.obj)中调用你的处理程序,处理完后即会停止自己的服务。 -
意思是
Intent的生命周期跟你的处理的任务是一致的,所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。
4.3.6 总结 IntentService 的特征有:
-
会创建独立的
worker线程来处理所有的Intent请求; -
会创建独立的
worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题; -
所有请求处理完成后,
IntentService会自动停止,无需调用stopSelf()方法停止Service;
第五篇:Service 与 Activity
5.1 Activity 怎么和 Service 绑定,怎么在 Activity 中启动对应的 Service
-
Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定,当绑定成功的时候Service会将代理对象通过回调的形式传给conn,这样我们就拿到了Service提供的服务代理对象。 -
在
Activity中可以通过startService和bindService方法启动Service。一般情况下如果想获取Service的服务对象那么肯定需要通过bindService()方法,比如音乐播放器,第三方支付等。 -
如果仅仅只是为了开启一个后台任务那么可以使用
startService()方法。
5.2 说说 Activity 、Intent 、Service 是什么关系
-
他们都是
Android开发中使用频率最高的类。其中Activity和Service都属于Android的四大组件。他俩都是Context类的子类ContextWrapper的子类,因此他俩可以算是兄弟关系吧。 -
不过他们各有各自的本领,
Activity负责用户界面的显示和交互,Service负责后台任务的处理。 -
Activity和Service之间可以通过Intent传递数据,因此可以把Intent看作是通信使者。
5.3 Service 和 Activity 在同一个线程吗
对于同一 app 来说默认情况下是在同一个线程中的,main Thread ( UI Thread )。
5.4 Service 里面可以弹吐司么
- 可以
- 弹吐司有个条件是:得有一个
Context上下文,而Service本身就是Context的子类 - 因此在
Service里面弹吐司是完全可以的。比如我们在Service中完成下载任务后可以弹一个吐司通知给用户。
5.5 与 Service 交互方式
5.5.1 广播交互
-
Server端将目前的下载进度,通过广播的方式发送出来,Client端注册此广播的监听器,当获取到该广播后,将广播中当前的下载进度解析出来并更新到界面上。 -
定义自己的广播,这样在不同的
Activity、Service以及应用程序之间,就可以通过广播来实现交互。
5.5.2 共享文件交互
- 我们使用
SharedPreferences来实现共享,当然也可以使用其它IO方法实现,通过这种方式实现交互时需要注意,对于文件的读写的时候,同一时间只能一方读一方写,不能两方同时写。 Server端将当前下载进度写入共享文件中,Client端通过读取共享文件中的下载进度,并更新到主界面上。
5.5.3 Messenger 交互 ( 信使交互 )
Messenger翻译过来指的是信使,它引用了一个Handler对象,别人能够向它发送消息 ( 使用mMessenger.send ( Message msg )方法)。- 该类允许跨进程间基于
Message通信,在服务端使用Handler创建一个Messenger,客户端只要获得这个服务端的Messenger对象就可以与服务端通信了 - 在
Server端与 Client 端之间通过一个Messenger对象来传递消息,该对象类似于信息中转站,所有信息通过该对象携带
5.5.4 自定义接口交互
- 其实就是我们自己通过接口的实现来达到
Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和AIDL非常类似 - 自定义一个接口,该接口中有一个获取当前下载进度的空方法。
Server端用一个类继承自Binder并实现该接口,覆写了其中获取当前下载进度的方法。Client端通过ServiceConnection获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。
5.5.5 AIDL 交互
- 远程服务一般通过
AIDL来实现,可以进行进程间通信,这种服务也就是远程服务。 AIDL属于Android的IPC机制,常用于跨进程通信,主要实现原理基于底层Binder机制。
第六篇:使用
6.1 什么情况下会使用 Service
<service android:enabled="true"/"false"
android:exported="true"/"false"
android:icon="drawable resource"
android:isolatedProcess="true"/"false"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string" >
</service>
-
android:enabled : 如果为true,则这个service可以被系统实例化,如果为false,则不行。默认为true
-
android:exported : 如果为true,则其他应用的组件也可以调用这个service并且可以与它进行互动,如果为false,则只有与service同一个应用或者相同user ID的应用可以开启或绑定此service。它的默认值取决于service是否有intent filters。如果一个filter都没有,就意味着只有指定了service的准确的类名才能调用,也就是说这个service只能应用内部使用,其他的应用不知道它的类名。这种情况下exported的默认值就为false。反之,只要有了一个filter,就意味着service是考虑到外界使用的情况的,这时exported的默认值就为true
-
android:icon : 一个象征着这个service的icon
-
android:label : 显示给用户的这个service的名字。如果不设置,将会默认使用的label属性。
-
android:name : 这个service的路径名,例如“com.liangkui.demo.MyService”。这个属性是唯一一个必须填的属性。
-
android:permission : 其他组件必须具有所填的权限才能启动这个service。
-
android:process : service运行的进程的name。默认启动的service是运行在主进程中的。(注意:如android:process=":ramote" 一定要带冒号不然会跑不起来)
6.1.1 经验总结:
Service其实就是背地搞事情,又不想让别人知道- 举一个生活当中的例子,你想知道一件事情不需要直接去问,你可以通过侧面了解。这就是
Service设计的初衷
6.1.2 Service 为什么被设计出来
-
根据
Service的定义,我们可以知道需要长期在后台进行的工作我们需要将其放在Service中去做。 -
得再通熟易懂一点,就是不能放在
Activity中来执行的工作就必须得放到Service中去做。 -
如:音乐播放、下载、上传大文件、定时关闭应用等功能。这些功能如果放到
Activity中做的话,那么Activity退出被销毁了的话,那这些功能也就停止了,这显然是不符合我们的设计要求的,所以要将他们放在Service中去执行。
6.2 onStartCommand() 返回值 int 值的区别
6.2.1 START_STICKY :
- 如果
service进程被 kill 掉,保留service的状态为开始状态,但不保留递送的intent对象。 - 随后系统会尝试重新创建
service, 由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand ( Intent, int, int )方法。 - 如果在此期间没有任何启动命令被传递到
service, 那么参数Intent将为null。
6.2.2 START_NOT_STICKY :
- “非粘性的”。
- 使用这个返回值时 , 如果在执行完
onStartCommand后 , 服务被异常kill掉 ,系统不会自动重启该服务。
6.2.3 START_REDELIVER_INTENT:
- 重传
Intent。 - 使用这个返回值时,如果在执行完
onStartCommand后,服务被异常 kill 掉 - 系统会自动重启该服务 , 并将 Intent 的值传入。
6.2.4 START_STICKY_COMPATIBILITY:
START_STICKY的兼容版本 , 但不保证服务被kill后一定能重启。
6.3 在 service 的生命周期方法 onstartConmand() 可不可以执行网络操作?如何在 service 中执行网络操作?
- 可以直接在
Service中执行网络操作 - 在
onStartCommand()方法中可以执行网络操作
6.4 提高 service 的优先级
-
在
AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时实用于广播。 -
在
onStartCommand里面调用startForeground()方法把Service提升为前台进程级别,然后再onDestroy里面要记得调用stopForeground ()方法。 -
onStartCommand方法,手动返回START_STICKY。 -
在
onDestroy方法里发广播重启service。
service+broadcast方式,就是当service走ondestory的时候,发送一个自定义的广播- 当收到广播的时候,重新启动
service。( 第三方应用或是在setting里-应用强制停止时,APP进程就直接被干掉了,onDestroy方法都进不来,所以无法保证会执行 )
- 监听系统广播判断
Service状态。
- 通过系统的一些广播
- 比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的
Service是否还存活。
Application加上Persistent属性。
6.5 Service 的 onRebind ( Intent ) 方法在什么情况下会执行
- 如果在
onUnbind()方法返回true的情况下会执行 , 否则不执行。