Service是Android的四大组件之一,是没有交互界面,运行在后台的服务程序。和Activity组件一样,也需要在清单文件里注册、由Intent对象去激活。
一、系统服务
Android后台有很多Service在系统启动时就被开启的,这些系统服务可以通过getSystemService()方法调用。
下面以振动器服务为例说明
实现步骤:
1、在清单文件声明权限
2、使用方法getSystemService(String name)得到振动器Vibrator对象,该方法以类Context中定义了系统服务常量为参数,返回Object类型,所以需要强制转换。
3、振动器对象调用vibrate()方法开始振动。
代码展示:
1、清单文件
2、Activity的onCreate()方法内加上如下代码:
Vibrator mVibrator=(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);//得到振动器Vibrator对象 mVibrator.vibrate(500);//开始振动,振动0.5秒
PS:MountService监听是否有SD卡安装及移除、ClipboardService提供剪切板功能、PackageManagerService提供软件包的安装和移除及查看等,部分常用系统服务可以参考:Android Service--系统服务类的使用
二、非绑定式服务
关于Service的定义、生命周期和绑定、非绑定式的区别,具体可以看菜鸟教程:Service初涉
这里我们可以理解非绑定式服务就是Activity与Service的生命周期是不相关的,如果Activity不调用stopService()停止服务,那么服务会一直存在于后台,即使Activity摧毁onDestroy了服务也还在。绑定式服务就是Activity与Service的绑定后,只要Activity摧毁onDestroy了服务也跟着摧毁了。
非绑定式服务的使用教程:
1、新建一个Service的子类取名UnBindService.java,重写回调方法onCreate()、onstartCommand()、onDestroy()。
2、在回调方法里调用音乐播放器MediaPlayer(这里用播放音乐为例)
3、在清单文件注册该服务,如果不注册Android Studio不会报错但是服务不会运行
4、在Activity里使用startService(intent)启动服务[该服务会自动调用图中的onCreate()和onstartCommand()],使用stopService(intent)停止服务[该服务会自动调用图中的onDestroy()]
代码展示:
UnBindService.java
public class UnBindService extends Service { /*这是一个非绑定式的后台播放音乐的服务 *需要在清单文件定义这个<service> *然后在activity里创建意图intent并调用Context的方法startService(intent)来启动服务 */ MediaPlayer mp; @Override public void onCreate() { super.onCreate(); mp=MediaPlayer.create(getApplicationContext(),R.raw.music);// res/raw/music.mp3,提前复制mp3文件粘贴到raw文件夹下 mp.start(); Log.d("myService","onCreat()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { /*参数介绍 * START_STICKY:service:系统内存紧张时会杀掉服务并尝试重新创建,但不保留intent * START_NOT_STICKY:在系统内存紧张的情况下需要被杀掉,且不会立即重新创建 * START_REDELIVER_INTENT:系统在崩溃后会重新启动服务,并重新传递在崩溃时存在的intent*/ Log.d("myService","onStartCommand()"); return START_NOT_STICKY; } @Override public void onDestroy() { super.onDestroy(); Log.d("myService","onDestroy()"); mp.stop();//停止播放器 if(mp!=null){mp=null;} } @Nullable @Override public IBinder onBind(Intent intent) {//Service的子类必须重写onBind(),但非绑定式可以不修改该方法 Log.d("myService","onBind()"); return null; } }
清单文件:(显示调用的写法)
MainActivity.java (布局文件里有两个按钮button1和button2)
public class MainActivity extends AppCompatActivity implements View.OnClickListener { Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Log.d("myService","这里调用了Activity的onCreate()");
intent=new Intent(MainActivity.this,UnBindService.class);//显示调用的写法 Button button1=this.findViewById(R.id.button1);//点击button1可以播放音乐 button1.setOnClickListener(this); Button button2=this.findViewById(R.id.button2);//点击button2可以停止音乐 button2.setOnClickListener(this); @Override public void onClick(View v) { switch(v.getId()){ case R.id.button1:startService(intent);break;//服务自动调用生命周期的回调函数onCreate、onStartCommand case R.id.button2:stopService(intent);break;//服务自动调用生命周期的回调函数onDestroy } } @Override protected void onDestroy() { super.onDestroy(); Log.d("myService","这里调用了Activity的onDestroy()"); } }
打开Android Studio的Logcat面板可以看到日志Log
从日志也可以看出,非绑定式Service的生命周期与Activity的生命周期是没有关系的
三、绑定式服务
绑定式服务比非绑定式多了一个内部类(Binder的子类)和回调方法onUnbind(),启动服务的方法也不同:是Context的方法bindService()
非绑定式服务的使用步骤:
1、新建一个Service的子类取名BindService.java,重写回调方法onCreate()、onBind()、onUnbind()、onDestroy()。
2、在回调方法里调用音乐播放器MediaPlayer(这里以播放音乐为例)
3、在清单文件注册该服务,如果不注册Android Studio不会报错但是服务不会运行
4、在Activity里创建服务连接ServiceConnection对象,该对象在绑定服务bindService()时创建,并得到代理人对象(Binder的子类对象),再通过代理人得到绑定式服务的对象。
5、使用bindService()绑定服务[ 该服务会自动调用生命周期的onCreate()和onBind() ,多个activity绑定时,只有第一个activity绑定时服务会onCreate()];使用unbindService()停止服务[该服务会自动调用生命周期的onUnbind()和onDestroy(),多个activity绑定的话则在最后一个activity解除绑定后,自动调用onDestroy() ]
代码展示:
BindService.java
public class BindService extends Service { public class MyBinder extends Binder {
/*得到服务的对象:
*非绑定式和绑定一样,通过Context的启动/绑定方法来创建服务,无需客户端new一个服务对象,那么要想得到这个服务对象必须通过代理模式,由代理人(Binder)返回这个对象
*IBinder是接口,Binder是实现接口的实例
*/ BindService getService(){ return BindService.this; } } MediaPlayer mp;//播放器对象 IBinder binder=new MyBinder();//代理模式,通过binder得到BindService服务对象 @Override public void onCreate() { super.onCreate(); Log.d("myService","onCreate()"); mp=MediaPlayer.create(getApplicationContext(),R.raw.music);// res/raw/music.mp3 提前复制mp3文件粘贴到raw文件夹下 } @Nullable @Override public IBinder onBind(Intent intent) { Log.d("myService","onBind()"); return binder;//代理人 } @Override public boolean onUnbind(Intent intent) { Log.d("myService","onUnbind()"); return super.onUnbind(intent); } @Override public void onDestroy() { super.onDestroy(); Log.d("myService","onDestroy()"); mp.stop(); if(mp!=null){mp=null;} } //以下是客户端可以通过服务对象调用的服务方法 public void playMusic(){ mp.start();}//播放器开始播放音乐 public void pauseMusic(){ mp.pause();}//播放器暂停音乐 public void stopMusic(){ mp.stop();}//播放器停止播放(和暂停不同,停止之后再次start时,会从头开始播放音乐) }
清单文件
蓝色方框内的代码为隐式调用服务时,需要内嵌的标签,action是作为过滤的条件。无论是绑定还是非绑定式的都可以选择使用显式或隐式方式来调用服务
MainActivity.java(布局文件有三个按钮:button3、button4、button5)
public class MainActivity extends AppCompatActivity implements View.OnClickListener { Intent mintent; Button button3,button4,button5; BindService mBindService; private ServiceConnection mConnection= new ServiceConnection() {//该服务连接对象只有在bindService()被调用时才会被创建 @Override public void onServiceConnected(ComponentName name, IBinder service) {
//(这里的service其实是BindService里onBind()返回的代理人) BindService.MyBinder mbinder=(BindService.MyBinder)service;//将上转型对象service强制转换回来 mBindService =mbinder.getService();//得到了绑定服务时自动创建的服务对象 Log.d("myService","连接成功"); } @Override public void onServiceDisconnected(ComponentName name) { //当service所在的进程*中止时,会通过该方法通知客户端服务已断开(调用unbindService()不会触发该方法) Log.d("myService","无法连接"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d("myService","这里调用了Activity的onCreate()"); //隐式调用服务组件
//隐式调用不像显式调用那样,直接指定服务,而是通过包名和action的name属性值来判断使用的是哪个服务 mintent=new Intent("ok");//"ok"为action值 mintent.setPackage("com.example.service");//参数为当前应用包名 bindService(mintent,mConnection,Context.BIND_AUTO_CREATE);//与服务绑定,服务调用onCreate()和onBind() /*参数介绍 *Context.BIND_AUTO_CREATE:绑定时自动创建Service */ button3=findViewById(R.id.button3); button4=findViewById(R.id.button4);
button5=findViewById(R.id.button5); button3.setOnClickListener(this); button4.setOnClickListener(this);
button5.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.button3:
mBindService.playMusic();
Log.d("myService","播放音乐");
break;//播放器开始播放音乐 case R.id.button4:
mBindService.pauseMusic();
Log.d("myService","暂停音乐");
break;//播放器暂停音乐 case R.id.button5: mBindService.stopMusic();
Log.d("myService","停止音乐"); MainActivity.this.unbindService(mConnection);//Activity与服务解绑,服务调用onUnbind()和onDestroy() break; } } @Override protected void onDestroy() { super.onDestroy(); Log.d("myService","这里调用了Activity的onDestroy()"); } }
打开Android Studio的Logcat面板可以看到日志Log
从Log可以看得出来,绑定了Activity之后的服务在Activity摧毁后也会跟着摧毁,那么绑定式服务就没办法实现 在退出应用后在后台播放音乐的操作。
还有一点就是,绑定式服务在调用者(Activity)的生命周期内 [ onCreate()--onDestroy() ], 只能调用一次bindService()和unbindService(),这点不像非绑定式服务可以在调用者生命周期内可以多次调用startService()和stopService()
还有一种使用服务的方式,就是先用startService()启动服务,然后再bindService()绑定服务,看一下菜鸟教程的介绍如下:
我利用前面的绑定式服务的例子,只做了以下修改:1、给BindService.java添加了回调函数onStartCommand()和onRebind() ;2、让onUnbind()返回true ;3、修改了MainActivity.java里启动服务的方法:先startService(mintent); 然后 bindService(mintent,conn,Context.BIND_AUTO_CREATE);4、再添加一个按钮button6来stopService(mintent);其他内容与上述例子代码相同,这里就不粘贴了,给大家展示一下日志吧:
这种方式相当于,绑定式和非绑定式的结合,当我们希望服务里的任务可以在后台也能进行时,可以把任务写到onStartCommand();当我们希望任务只在activity的生命周期内进行时,可以把任务写入内部方法,利用绑定式服务的对象调用内部方法;而且不用担心最后一个activity与服务解绑后服务会被摧毁,事实上,这里只能通过stopService()来摧毁服务,这点和非绑定式相同。