介绍
Service可以理解成为是一个没有布局的Activity
典型的场景:
- 音乐后台播放
- 后台下载
Service和Activity都是运行在主线程中的,都是可以有线程,Service和Activity都可以理解成一个车间,里面有一个个流水线(线程),且二者都不能进行耗时操作。
创建Service
- 继承系统的Serivce类,然后新建一个自己的Service类(Myservice)
首先继承的是android.app.Service下的包。
- 重写其中的重要方法
必须重写onBind方法,选择性重写其他方法。
- 在Manifest中注册Service
<service android:name=“.service.Myservice” />
1)启动方式
1、非绑定式启动Service
通过intent启动。
有两个特点:
- 一旦启动服务就跟启动者没什么关系了,即使启动者app销毁,Service依旧在后台运行。
- 启动者无法调用Service类的方法。
public void startService(View view){
Intent i=new Intent(this,Myservice.class);
startService(i);
}
2、绑定式启动Service
绑定式启动有两个特点:
- 一旦启动服务就跟启动者的生命周期绑定在一起,启动者app销毁,Service也销毁。
- 启动者可以调用Service类的方法。
1.初始化
只要在Activity启动者点击启动服务后,会先调用Service的onCreate方法,然后再调用onBind方法返回一个IBinder 变量给到Activity启动者,然后Activity启动者会调用onServiceConnected方法(因为连接成功了,此方法会被回调)。
//启动者Activity
public class MainActivity extends AppCompatActivity{
//用来保存MyBinder类的对象,方便全局调用
private Myservice2.MyMyBinder mBinder=null;
//因为启动类可以调用Service类的方法,所以有这个连接的实现
private ServiceConnection conn=new ServiceConnection(){
@Override
//第二个参数指的就是我们被绑定的service,成功绑定的时候会调用此方法
public void onServiceConnected(ComponentName name,IBinder service){
mBinder=(Myservice2.MyMyBinder)service;
mBinder.test();
}
@Override
//解除Binder绑定的时候会回调此方法
public void onServiceDisConnected(ComponentName name){
}
}
@Override
//这个方法不是重点
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
...
//点击按钮后,点击事件就会绑定式启动服务
public void startService(View view){
Intent i=new Intent(this,Myservice2.class);
bindService(i,conn,BIND_AUTO_CREATE);
}
public class Myservice2 extends Service{
private static final String TAG= "Myservice2";
//当被启动类启动且被绑定后会被回调此方法
//要返回一个IBinder对象,但没有IBinder对象
//所以可以创建一个内部类MyBinder继承IBinder
@Nullable
@Override
public IBinder onBind(Intent intent){
....
return new MyBinder();
}
@Override
//启动者销毁后会先调用这个方法再onDestroy()
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
//Binder已经实现了IBinder接口
//public方便Activity启动类把Binder强转为IBinder父类
public class MyBinder extends Binder{
}
}
在启动者Activity中,想要调用Service里面的方法,就可以用Activity中的mBinder去调用了。
2.Activity启动类调用Service类的Myservice内部类方法
那么现在我们的MyBinder内部类里面是我们自己定义的,里面什么方法都没有,我们该怎么调用呢?
可以自己定义一个方法,比如test()等,单独打印一个日志也是可以的。
因为返回给到Activity的就是MyBinder 类的对象,所以MyBinder 类里面的方法可以随便调用。
public class Myservice2 extends Service{
private static final String TAG= "Myservice2";
//当被启动类启动且被绑定后会被回调此方法
//要返回一个IBinder对象,但没有IBinder对象
//所以可以创建一个内部类MyBinder继承IBinder
@Nullable
@Override
public IBinder onBind(Intent intent){
....
return new MyBinder();
}
@Override
//启动者销毁后会先调用这个方法再onDestroy()
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
//Binder已经实现了IBinder接口
//public方便Activity启动类把Binder强转为IBinder父类
public class MyBinder extends Binder{
public void test(){
Log.d(TAG,"Myservice调用了自己的test方法");
}
}
}
3.Activity启动类调用Service类的方法
那启动者只能获取到内部MyBinder类的方法吗?
怎么获取到Service类的方法呢?
因为返回给到Activity的就是MyBinder 类的对象,所以MyBinder 类里面的方法和变量可以随便调用,我们在MyBinder 类里面保存了一个Service对象,所以可以调用的到Service方法。
public class Myservice2 extends Service{
private static final String TAG= "Myservice2";
//当被启动类启动且被绑定后会被回调此方法
//要返回一个IBinder对象,但没有IBinder对象
//所以可以创建一个内部类MyBinder继承IBinder
public IBinder onBind(Intent intent){
....
//new一个Myservice实例出来,传入Service对象!!(重点)
return new MyBinder(this);
}
@Override
//启动者销毁后会先调用这个方法再onDestroy()
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
//测试方法
public void test1(){
Log.d(TAG,"我是服务");
}
//Binder已经实现了IBinder接口
//public方便Activity启动类把Binder强转为IBinder父类
public class MyBinder extends Binder{
//Service类对象
private Myservice2 mMyservice2;
//构造
public MyBinder(Myservice2 myservice2){
mMyservice2=myservice2;
}
//测试方法
public void test(){
Log.d(TAG,"Myservice调用了自己的test方法");
//调用到Service类的方法
mMyservice2.test1();
}
}
}
最后退出Activity后,服务也会跟着销毁。
2)生命周期
1、非绑定式启动Service
启动阶段:Activity调用bindService
onCreate()
:只会在首次创建执行一次onBind()
:只会在首次绑定时执行一次,后续再bindService也不会执行了
结束阶段:启动者Activity销毁,或者调用unbindService()
会解绑Service。当没有绑定者时,该Service会销毁。
onUnbind
:Service解除绑定onDestroy
:服务销毁前的最后一个方法,可以做些资源释放工作。
1.手动停止服务
public void stopService(){
unbindService(conn);
}
2、绑定式启动Service
启动阶段:Activity调用startService
onCreate()
:只会在首次创建执行一次onStartCommand()
:每次startService都会执行一次(无论服务是否正在运行)
结束阶段:启动者Activity调用stopService()
或service内部调用stopSelf()
onDestroy
:服务销毁前的最后一个方法,可以做些资源释放工作。
1.stopService()手动停止服务
重新搞一个按钮点击事件
public void stopService(View view){
Intent i=new Intent(this,Myservice.class);
stopService(i);
}
2.stopSelf()判断停止服务
通过传入的intent参数值判断是否需要停止服务
//在Activity中点击事件
public void stopService(View view){
Intent i=new Intent(this,Myservice.class);
i.putExtra("key_stop","stop");
startService(i);
}
//在服务类的内部
public class myservice extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String v=intent.getStringExtra("key_stop");
if(TextUtils.equals(v,stop)){
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
}
3.stopSelf()通过时间停止服务
Activity正常的绑定式启动服务。
//在服务类的内部,延时5s后退出
public class myservice extends Service {
@Override
public void onCreate() {
super.onCreate();
Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
stopSelf();
}
},5000);
}
}
3)特殊:前台Service
前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。
前台Service就类似于音乐播放器播放的时候任务栏显示的通知,算是一种特殊的Service类型。
所以它是可以在前台和用户进行交互的Service,所以优先级自然比后台看不见的Service要高,几乎不会被系统回收。
前台服务必须显示通知(Notification),所以是以通知的形式呈现的,且该通知时不可去除的,除非服务停止或者从前台移除。
那么,如果我们希望Service可以一直保持运行状态且不会在内存不足的情况下被回收时,可以选择将需要保持运行的Service设置为前台服务。