介绍
Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件。Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。
Android中的服务Service,和Activity不同的是不能与用户交互的,不能自己启动,系统的后台运行,当程序退出时,我们没有显示的调用停止服务,那么这个Service就没有结束,它仍然在后台运行。Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的操作。
服务一般分为两种:
Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。
service在清单文件中的声明
不管是哪一种的 service ,也都需要在 AndroidManifest.xml中声明
<service android:name=".myservice"
android:enabled="true"
android:exported="true"
android:icon="@drawable/background_blue"
android:label="string"
android:process="string"
android:permission="string">
</service>
说明:
字段 | 说明 |
---|---|
android:exported | 表示是否允许除了当前程序之外的其他程序访问这个服务 |
android:enabled | 表示是否启用这个服务 |
android:permission | 是权限声明 |
android:process | 是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。 |
android:isolatedProcess | 设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。 |
生命周期
Service 的的生命周期会根据调用不同的方法启动有不同的表现,具体有两种形式。
说明:
1.startService / stopService
生命周期顺序:onCreate->onStartCommand->onDestroy
OnCreate()
系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果service已经运行,这个方法不会被调用。
onStartCommand()
每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务。
OnDestory()
系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。
2.bindService / unbindService
生命周期顺序:onCreate->onBind->onUnBind->onDestroy 同样首先是OnCreate(),接着是
OnBind() 当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。
OnUnbind() 当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。
最后是OnDestory()
注意:通过bindService启动的Service的生命周期依附于启动它的Context。
start开启服务的生命周期:
start开启服务的生命周期特点:
1. 服务可以被开启多次,每次开启都调用onStartCommand
2. 服务只能被停止一
3. 长期运行在后台
bind绑定服务的生命周期
bind绑定服务的生命周期特点:
1. 服务只能被绑定一次,多次绑定无效
2. 服务只能被解绑一次,多次解绑会抛出异常
3. activity和绑定的Service是同生共死
4. 绑定服务调用服务里的方法
区别
IntentService与Service
Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。
Service的官方介绍
1.Service不是一个单独的进程 ,它和应用程序在同一个进程中。
2.Service不是一个线程,所以我们应该避免在Service里面进行耗时的操作 IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务。
IntentService有以下特点:
1.它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。
2.创建了一个工作队列,来逐个发送intent给onHandleIntent()。
3.不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
4.默认实现的onBind()返回null
5. 默认实现的onStartCommand()的目的是将intent插入到工作队列中
继承IntentService的类至少要实现两个函数:构造函数和onHandleIntent()函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数
示例:
package com.loaderman.intentservicedemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,MyService.class));//主界面阻塞,最终会出现Application not responding
//连续两次启动IntentService,会发现应用程序不会阻塞,而且最重要的是第二次的请求会再第一个请求结束之后运行(这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)
startService(new Intent(this,MyIntentService.class));
startService(new Intent(this,MyIntentService.class));
}
}
package com.loaderman.intentservicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
//经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作
System.out.println("onStart");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠结束");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
package com.loaderman.intentservicedemo;
import android.app.IntentService;
import android.content.Intent;
public class MyIntentService extends IntentService {
public MyIntentService() {
super("loaderman");
}
@Override
protected void onHandleIntent(Intent intent) {
// 经测试,IntentService里面是可以进行耗时的操作的
//IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent
//对于异步的startService请求,IntentService会处理完成一个之后再处理第二个
System.out.println("onStart");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠结束");
}
}
能否保证service不被杀死?
Service设置成START_STICKY kill
后会被重启(等待5秒左右),重传Intent,保持与重启前一样
提升service优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效
提升service进程优先级
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收
当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。
【结论】如果在极度极度低内存的压力下,该service还是会被kill掉,并且不一定会restart()
onDestroy方法里重启service
service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service
也可以直接在onDestroy()里startService
【结论】当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证
监听系统广播判断Service状态
通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限
【结论】这也能算是一种措施,不过感觉监听多了会导致Service很混乱,带来诸多不便
在JNI层,用C代码fork一个进程出来
这样产生的进程,会被系统认为是两个不同的进程.但是Android5.0之后可能不行
root之后放到system/app变成系统级应用