目录
Service拥有自己的生命周期,不会被捆绑,即便Activity销毁之后,Service也不会销毁。
绑定服务的最大作用就是用来实现对Service执行的任务进行进度监控。
Android四大组件:
Activity,Service,BroadcastReceiver,ContentProvider。
-——————————————————————————————————————————-
1.1 概念
Service(服务)是一个长期运行在后台,没有用户界面的应用组件,即使切换到另一个应用程序或者后台,服务也可以正常运行。因此,服务适合执行一段时间不需要显示界面的后台耗时操作****(需要另启子线程),比如下载网络数据,播放音乐等。
1 Service可以看做是一个没有界面的Activity,因此启动,销毁服务跟开启,销毁Activity类似Service并不是运行在一个独立的进程当中,而是依赖于创建服务时所在的应用程序进程,即Service运行在主线程中。当某个应用程序进行被杀掉时,所有依赖于该进程的服务都会停止运行。
Service并不会自动开启线程,所有的代码都是默认运行在主线程当中的,也就是说,需要在服务的内部手动创建子线程,并在里面执行具体的任务。否则就会出现主线程被阻塞的情况。
Activity启动服务,主要用于响应和处理Activity的事件。Service拥有自己的生命周期,不会被捆绑,即便Activity销毁之后,Service也不会销毁。 支持显式和隐式启动服务。
1.2 适用场景
1)下载网络数据****(在Android3.0之后,只支持子线程下载,因此此功能应该在子线程中启动服务)。
2)播放音乐。
3)访问文件、数据库等一些业务逻辑功能,可以让Service来实现。
1.3 继承结构图
比较Service与Activity的继承关系结构图如下:
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.1 创建类并继承Service
Service(服务)是Android四大组件之一。创建方式与广播接收者类似。【new】->【Service】,创建的Service如下所示:
1 public class MyService extends Service{public IBinder onBind(Intent intent) {public int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);public boolean onUnbind(Intent intent) {return super.onUnbind(intent);public void onDestroy() {3.2 注册服务
Service创建后,会在清单文件AndroidManifest.xml中进行注册,如下所示:
1 android:name="com.example.service.MyService"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类:
1 public class MyService extends Service{public IBinder onBind(Intent intent) {class MyBinder extends Binder{public void methodInService(){public boolean onUnbind(Intent intent) {return super.onUnbind(intent);可以看出,Binder是实现了IBinder接口。从而在Binder类里面可以自定义方法。
Activity类:
1 public class MainActivity extends AppCompatActivity{private MyServiceConnection connection; protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);public void btnBind(View view){ connection = new MyServiceConnection(); Intent intent = new Intent(this,MyService.class); //绑定服务,BIND_AUTO_CREATE表示绑定时自动创建ServicebindService(intent,connection,BIND_AUTO_CREATE);public void btnUnbind(View view){ unbindService(connection);public void btnCallServiceInMethod(View view){public class MyServiceConnection implements ServiceConnection{public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i("MainActivity","服务绑定成功,内存地址为:"+iBinder.toString());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)重新创建:如果系统发生异常导致服务终止后,如果内存足够,服务所在的进程会重新创建服务。如果是用户主动销毁的,则不会重新创建。
1 在Android中绑定式服务bindService会随着Activity的结束而结束,但是启动式服务startService不受Activity的影响。
通过绑定方式开启服务后,服务与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之外,其他类型全部都需要导入到包,即使它们在同一个包中。
下面一个音乐播放器案例演示本地服务通信:
布局文件:
1 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/back1"android:orientation="vertical">android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/musicplayer_et_inputpath"android:text="Mucis/a.mp3"android:textColor="#FFEEF608"/>android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:layout_gravity="center_vertical"android:orientation="horizontal">android:id="@+id/musicplayer_tv_paly"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="#FFFFFF"android:drawableTop="@drawable/weibo"android:drawablePadding="3dp"android:gravity="center"/>android:id="@+id/musicplayer_tv_pause"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="#FFFFFF"android:drawableTop="@drawable/weixin"android:drawablePadding="3dp"android:gravity="center"/>Service类:
1 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){ mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(path); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){public void onPrepared(MediaPlayer mp){if(mediaPlayer != null && mediaPlayer.isPlaying()){ }else if(mediaPlayer != null && (!mediaPlayer.isPlaying())){public int getCurrentProgress(){if(mediaPlayer != null && mediaPlayer.isPlaying()){return mediaPlayer.getCurrentPosition(); }else if(mediaPlayer != null && (!mediaPlayer.isPlaying())){return mediaPlayer.getCurrentPosition();public IBinder onBind(Intent intent) {上述代码使用了MediaPlayer类来实现音乐播放功能,其常用方法如下:
》setAudioStreamType():指定音频文件的类型,必须在prepare()方法之前使用。
》setDataSource():设置要播放的音频文件的位置,即URI路径,
》prepare():准备播放,调用此方法会使MediaPlayer进入准备状态。
》start():开始或继续播放音频。
》pause():暂停播放音频。
》seekTo():从指定的位置开始播放音频。
》release():释放掉与MediaPlayer对象相关的资源。
》isPlaying():判断当前MediaPlayer是否正在播放音频。
》getCurrentPosition():获取当前播放音频文件的位置。
Activity类:
1 public class MusicPlayerActivity extends AppCompatActivity implements View.OnClickListener{ MusicPlayerService.MyBinder binder;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); 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();case R.id.musicplayer_tv_paly:if (file.exists() && file.length() > 0) { Toast.makeText(this, "找不到音乐文件", Toast.LENGTH_SHORT).show();case R.id.musicplayer_tv_pause:protected void onDestory(){