目录
Android四大组件:
1. 服务的概念
1.1 概念
1.2 适用场景
1.3 继承结构图
2. 服务的生命周期
2.1 定义
Service拥有自己的生命周期,不会被捆绑,即便Activity销毁之后,Service也不会销毁。
2.2 启动类型
2.3 结构图
2.4 方法
3. 服务的创建
3.1 创建类并继承Service
3.2 注册服务
3.3 服务启动方式
3.3.1 startService方式启动服务
3.3.2 bindService方式启动服务
3.4 bindService案例
3.4.1 bindService使用场景
绑定服务的最大作用就是用来实现对Service执行的任务进行进度监控。
3.4 服务的关闭与解绑方法
3.5 服务的启动模式
3.6 两种启动方法的区别
4 服务的通信
4.1 通信方式
Android四大组件:
Activity,Service,BroadcastReceiver,ContentProvider。
--------------------------------------------------------------------------------------------------------------------------------
1. 服务的概念
1.1 概念
Service(服务)是一个长期运行在后台,没有用户界面的应用组件,即使切换到另一个应用程序或者后台,服务也可以正常运行。因此,服务适合执行一段时间不需要显示界面的后台耗时操作(需要另启子线程),比如下载网络数据,播放音乐等。
Service可以看做是一个没有界面的Activity,因此启动,销毁服务跟开启,销毁Activity类似
Service并不是运行在一个独立的进程当中,而是依赖于创建服务时所在的应用程序进程,即Service运行在主线程中。当某个应用程序进行被杀掉时,所有依赖于该进程的服务都会停止运行。
Service并不会自动开启线程,所有的代码都是默认运行在主线程当中的,也就是说,需要在服务的内部手动创建子线程,并在里面执行具体的任务。否则就会出现主线程被阻塞的情况。
Activity启动服务,主要用于响应和处理Activity的事件。Service拥有自己的生命周期,不会被捆绑,即便Activity销毁之后,Service也不会销毁。 支持显式和隐式启动服务。
1.2 适用场景
1)下载网络数据(在Android3.0之后,只支持子线程下载,因此此功能应该在子线程中启动服务)。
2)播放音乐。
3)访问文件、数据库等一些业务逻辑功能,可以让Service来实现。
1.3 继承结构图
比较Service与Activity的继承关系结构图如下:
2. 服务的生命周期
2.1 定义
Service可以看做是一个没有界面的Activity。Service拥有自己的生命周期,不会被捆绑,即便Activity销毁之后,Service也不会销毁。
2.2 启动类型
服务的启动方式有两种,分别是startService()(启动服务)和bindService()(绑定服务)方法。使用不同的方法启动服务,其生命周期也是不同的。服务的启动都是在Activity中进行的。
1.startService() 其他组件调用startService()启动一个Service,一旦启动,Service将一直运行在后台,即便启动
Service的组件已经被destory。但是,Service会在后台执行单独的操作,也并不会给启动它的
组件返回结果。
比如说:一个以启动服务方式的Service执行在后台下载或者上传一个文件的操作,
完成之后,Service自动停止。
2.bindService() 其他组件调用bindService()绑定一个Service,通过绑定方式启动的Service是一个client-server
结构,该Service可以与绑定它的组件进行交互。一个绑定的Service仅在仅有组件与其绑定时才会运行,
多个组件可与一个Service绑定,Service不在与人和网组件绑定时,将会被destory
2.3 结构图
如下图所示:
2.4 方法
1.onCreate() 服务被创建,单例模式,只会创建一次 2.onStartCommand() 服务启动时调用 3.onBind() 绑定时调用,同时会调用onCreate()方法,不会调用onStartCommand()方法 4.onUnBind() 解绑时调用 ,同时会调用onDestory()方法 5.onDestory() 销毁时调用
3. 服务的创建
3.1 创建类并继承Service
Service(服务)是Android四大组件之一。创建方式与广播接收者类似。【new】->【Service】,创建的Service如下所示:
public class MyService extends Service{ //客户端通过调用bindService()方法启动服务时执行该方法 @Nullable @Override public IBinder onBind(Intent intent) { return null; } //客户端通过调用startService()方法启动服务时执行该方法,可以执行多次 @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); } //第一次创建服务时执行的方法,且只执行一次 @Override public void onCreate() { super.onCreate(); } //客户端调用unBindeService()方法断开服务绑定时执行该方法 @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } //服务被销毁时执行的方法,且只执行一次 @Override public void onDestroy() { super.onDestroy(); } }
3.2 注册服务
Service创建后,会在清单文件AndroidManifest.xml中进行注册,如下所示:
...... ...... ...... 3.3 服务启动方式
3.3.1 startService方式启动服务
startService(Intent intent), 传入Intent对象,通过startService方式启动服务,服务会长期在后台运行,并且服务的状态与开启者的状态没有关系,即便启动服务的组件已经被销毁,服务也依旧会运行。
3.3.2 bindService方式启动服务
通过bindService方式启动服务,服务会与组件进行绑定。一个被绑定的服务提供一个客户端与服务器接口,允许组件与服务进行交互,发送请求,得到结果。多个组件可以绑定一个服务,当调用onUnbind()方法时,这个服务就被销毁了,即调用onDestory()方法。
bindService()方法完整名为bindService(Intent service,ServiceConnection conn,int flags),该方法的三个参数解释如下:
Intent对象 用于指定要启动的Service。 ServiceConnection对象 用于监听调用者与Service之间的连接状态。当调用者与Service连接成功时,
将回调该对象的onServiceConnected(ComponentName name,IBinder service)方法。
断开连接时,将回调该对象的onServiceDisconnected(ComponentName name)方法。
flag 指绑定时是否自动创建Service(如果Service还未创建)。可指定为0,即不自动创建,
也可指定为“BIND_AUTO_CREATE”,即自动创建。
之所以需要ServiceConnection对象,是为了表示绑定与解绑某个具体Service。
3.4 bindService案例
3.4.1 bindService使用场景
绑定服务的最大作用就是用来实现对Service执行的任务进行进度监控。
需要使用的两个类如下:
1.ServiceConnection 是一个接口,主要在绑定服务中用于客户端和服务器端链接的,使用ServiceConnection时
通常要重写onServiceConnected()和OnServiceDisconnected()方法
2.IBinder 案例如下,Service类:
public class MyService extends Service{ //服务创建 @Override public void onCreate() { super.onCreate(); } //绑定服务 @Nullable @Override public IBinder onBind(Intent intent) { //返回一个Binder对象,Binder继承与IBinder return new MyBinder(); } //创建服务代理,调用服务中的方法 class MyBinder extends Binder{ methodInService(); } //自定义方法 public void methodInService(){ } //解绑 @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } }
可以看出,Binder是实现了IBinder接口。从而在Binder类里面可以自定义方法。
Activity类:
public class MainActivity extends AppCompatActivity{ private MyServiceConnection connection; //ServiceConnection对象 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //绑定服务 public void btnBind(View view){ if(connection == null){ connection = new MyServiceConnection(); } Intent intent = new Intent(this,MyService.class); //绑定服务,BIND_AUTO_CREATE表示绑定时自动创建Service bindService(intent,connection,BIND_AUTO_CREATE); } //解绑服务 public void btnUnbind(View view){ if(connection != null){ //解绑服务,这里需要传入ServiceConnection对象 unbindService(connection); connection = null; } } //调用绑定的服务里面的方法 public void btnCallServiceInMethod(View view){ } /** * 创建类继承ServiceConnection,用于解绑服务方法调用 */ public class MyServiceConnection implements ServiceConnection{ //当客户端正常连接这个服务时,成功绑定到服务时调用该方法。注意IBinder参数对象 @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //如果成功绑定,iBinder为MyService里面的IBinder对象 Log.i("MainActivity","服务绑定成功,内存地址为:"+iBinder.toString()); } //当客户端与服务失去连接时调用该方法 @Override public void onServiceDisconnected(ComponentName componentName) { //解绑 Log.i("MainActivity","服务解绑成功"); } } }
可以看出,onServiceConnected()方法里面的IBinder就是Service里面的onBinder()方法的返回IBinder对象。
3.4 服务的销毁方法
1)通过startService方式启动的服务时,销毁服务方法
通过stopService(Intent inetnt)方式;
2)通过bindService方式启动的服务时,销毁服务方法
通过unbindService(ServiceConnection conn)方式。
3.5 服务的启动模式
1)单例模式:Service在Android中是单例模式,即onCreate()与onDestory()只会被调用一次。
2)重新创建:如果系统发生异常导致服务终止后,如果内存足够,服务所在的进程会重新创建服务。如果是用户主动销毁的,则不会重新创建。
3.6 两种启动方法的区别
在Android中绑定式服务bindService会随着Activity的结束而结束,但是启动式服务startService不受Activity的影响。
4 服务的通信
通过绑定方式开启服务后,服务与Activity是可以通信的,通过Activity可以控制服务进行一些操作。
4.1 通信方式
在Android中,服务的通信方式有两种:本地服务通信和远程服务通信。使用这两种方式进行通信时,必须保证服务是以绑定的形式开启的,否则无法进行通信和数据交换。
1)本地服务通信
指的是应用程序内部的通信。首先需要创建一个Service类,该类会提供一个onBind()方法,onBind()方法的返回值是一个IBinder对象,IBinder对象会作为参数传递给ServiceConnection类中的onServiceConnected(ComponentName name,IBinder service)方法,这样访问者就可用通过IBinder对象与Service进行通信。如下图所示:
从上图可以看出,服务在进行通信时实际使用的是IBinder对象,在ServiceConnection类中得到的IBinder对象,通过这个对象可以获取到服务中自定义的方法,执行具体的操作。
2)远程服务通信
在Android系统中,各个应用程序都运行在自己的进程中,如果想要完成不同进程之间的通信,就需要用到远程服务通信。远程服务通信时通过AIDL(Android Interface Definition Language)实现的,接口定义语言,语法格式简单,与Java中定义接口类似,但存在差异如下:
》AUDL定义接口的源代码必须以.aidl结尾。
》AIDL接口中用到的数据类型,除了基本数据类型及String、List、Map、CharSequence之外,其他类型全部都需要导入到包,即使它们在同一个包中。
下面一个音乐播放器案例演示本地服务通信:
布局文件:
Service类:
public class MusicPlayerService extends Service { private static final String TAG = "MucisPalyerService"; public MediaPlayer mediaPlayer; public MusicPlayerService() { } class MyBinder extends Binder{ //播放音乐 public void play(String path){ try{ if(mediaPlayer == null){ //创建一个MediaPlayer播放器 mediaPlayer = new MediaPlayer(); //指定参数为音频文件 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); //指定播放的路径 mediaPlayer.setDataSource(path); //准备播放 mediaPlayer.prepare(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){ public void onPrepared(MediaPlayer mp){ //开始播放 mediaPlayer.start(); } }); }else{ //int position = getCurrent } }catch (Exception e){ e.printStackTrace(); } } //暂停播放 public void pause(){ if(mediaPlayer != null && mediaPlayer.isPlaying()){ mediaPlayer.pause(); }else if(mediaPlayer != null && (!mediaPlayer.isPlaying())){ mediaPlayer.start(); } } } public void onCreate(){ super.onCreate(); } //获取当前进度 public int getCurrentProgress(){ if(mediaPlayer != null && mediaPlayer.isPlaying()){ return mediaPlayer.getCurrentPosition(); }else if(mediaPlayer != null && (!mediaPlayer.isPlaying())){ return mediaPlayer.getCurrentPosition(); } return 0; } public void onDestory(){ if(mediaPlayer != null){ mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } super.onDestroy(); } @Override public IBinder onBind(Intent intent) { //第一步执行onBind方法 return new MyBinder(); } }
上述代码使用了MediaPlayer类来实现音乐播放功能,其常用方法如下:
》setAudioStreamType():指定音频文件的类型,必须在prepare()方法之前使用。
》setDataSource():设置要播放的音频文件的位置,即URI路径,
》prepare():准备播放,调用此方法会使MediaPlayer进入准备状态。
》start():开始或继续播放音频。
》pause():暂停播放音频。
》seekTo():从指定的位置开始播放音频。
》release():释放掉与MediaPlayer对象相关的资源。
》isPlaying():判断当前MediaPlayer是否正在播放音频。
》getCurrentPosition():获取当前播放音频文件的位置。
Activity类:
public class MusicPlayerActivity extends AppCompatActivity implements View.OnClickListener{ private EditText path; private Intent intent; private MyConn conn; MusicPlayerService.MyBinder binder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.musicplayer_layout); path = (EditText)findViewById(R.id.musicplayer_et_inputpath); findViewById(R.id.musicplayer_tv_paly).setOnClickListener(this); findViewById(R.id.musicplayer_tv_pause).setOnClickListener(this); conn = new MyConn(); intent = new Intent(this,MusicPlayerService.class); bindService(intent,conn,BIND_AUTO_CREATE); } private class MyConn implements ServiceConnection{ public void onServiceConnected (ComponentName name, IBinder service){ binder = (MusicPlayerService.MyBinder)service; } public void onServiceDisconnected(ComponentName name){ } } public void onClick(View v) { String pathway = path.getText().toString().trim(); File SDPath = Environment.getExternalStorageDirectory(); File file = new File(SDPath, pathway); String path = file.getAbsolutePath(); switch (v.getId()) { case R.id.musicplayer_tv_paly: if (file.exists() && file.length() > 0) { binder.play(path); } else { Toast.makeText(this, "找不到音乐文件", Toast.LENGTH_SHORT).show(); } break; case R.id.musicplayer_tv_pause: binder.pause(); break; default: break; } } protected void onDestory(){ unbindService(conn); super.onDestroy(); } }