MediaPlayer播放背景音乐(二)

本章目录

  • Part One:Service
  • Part Two:优化播放

Part One:Service

Service是Android中的四大应用组件(拥有声明周期方法)之一,它是一个可以在后台执行长时间耗时操作而不使用用户界面的应用组件。Service可由其他应用组件启动,而且即使用户切换到其他应用,Service仍将在后台继续运行。
需要注意的是:

  • Service是运行于后台,但是是服务进程。
  • Service可执行耗时操作,但是是运行在主线程。所以,耗时操作是在Service中启工作线程。
  • 因为当Activity工作于后台处于停止状态时,它所在进程的生命力就会比较薄弱,在内存不足时,可能会被杀死。
  1. 上面提到的服务进程,单独说一下。在Android中的进程按生命力高低,可以分为如下几种类型:
    前台进程(可见,可以与用户交互),例如,微信跟别人聊天。
    可见进程(可见,但是不能与用户交互),例如,对话框。
    服务进程(后台有service在运行),例如,下载。
    后台进程(没有service组件,所有的activity都处于停止状态),例如,微信聊天切换到别的应用。
    空进程(没有任何组件在运行的进程),保留这种进程的的唯一目的是用作缓存,以缩短该应用下次在其中运行组件所需的启动时间。
  2. Service的应用场合
    执行长时间耗时操作时,可以考虑在Service组件中执行,例如音乐的播放,音乐的下载等。
    但是,并不是耗时都要写到Service,短时间的耗时完全可以在Activity中启工作线程执行,例如普通网络请求。
  3. 如何使用Service
    要创建Service,必须创建 Service 的子类(或使用它的一个现有子类)。在实现中,需要重写一些回调方法,以处理Service生命周期的某些关键方面。
    并且,需要在AndroidManifest.xml中将Service注册。
    应重写的最重要的回调方法包括:
    • onStartCommand():当另一个应用组件通过调用 startService() 请求启动Service时,系统将调用此方法。一旦执行此方法,Service即会启动并可在后台无限期运行。 如果实现此方法,则在Service工作完成后,需要通过调用 stopSelf() 或 stopService() 来停止服务。(如果只想提供绑定,则无需实现此方法)。
    • onBind():当另一个组件想通过调用 bindService() 与Service绑定时,系统将调用此方法。在此方法的实现中,必须通过返回 IBinder 提供一个接口,供客户端用来与Service进行通信。必须要实现此方法,但如果并不希望允许绑定,则应返回 null。
    • onCreate():系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作(在调用它方法如onStartCommand()或onBind()之前)。如果service已经运行,这个方法不会被调用。
  • onDestroy():系统在Service不再被使用并要销毁时调用此方法。Service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等。这是Service收到的最后一个调用。
  1. 绑定模式Service
    绑定模式Service相当于在Activity端与Service端建立了一个长链接(ServiceConnection)。
    然后可以通过此长连接对象中的方法获得Service中返回的绑定对象。通过此对象调用Service中的一些业务方法。
    当采用Context.bindService()方法启动Service,与之相关的生命周期方法为:
    onCreate() -> onBind() -> onUnbind() -> onDestroy()
    • onBind():只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,并不会导致该方法被多次调用。
    • onUnbind():只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
  2. 启动模式Service
    启动Service由另一个组件通过调用 startService() 启动,此时会调用服务的 onStartCommand() 方法。Service启动之后,其生命周期即独立于启动它的组件,并且可以在后台无限期地运行,即使启动服务的组件已被销毁也不受影响。因此,Service应通过调用stopSelf() 结束工作来自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。
    应用组件(如 Activity)可以通过调用 startService() 方法并传递 Intent 对象 (指定服务并包含待使用服务的所有数据)来启动Service。Service通过onStartCommand() 方法接收此 Intent。
    当采用Context.startService()方法启动Service,与之相关的生命周期方法为:
    onCreate()--> onStart()--> onDestroy()
    onCreate():该方法在Service被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,Service也只被创建一次。
    onStart():只有采用Context.startService()方法启动Service时才会回调该方法。该方法在Service开始运行时被调用。多次调用startService()方法尽管不会多次创建Service,但onStart() 方法会被多次调用。
    onDestroy():该方法在Service被终止时调用。
    Service的粘性表现为其所在进程被意外中止后,该Service是否可以自动重新被启动。默认情况下,使用startService()方法激活的Service组件时粘性的,则即使所在进程被意外中止了,稍后该Service依然会被自动创建出来。
    onStartCommand有4种返回值:
    • START_STICKY:如果Service进程被kill掉,保留Service的状态为开始状态,但不保留递送的intent对象。
    • START_NOT_STICKY:使用这个返回值时,如果在执行完onStartCommand后,Service被异常kill掉,系统不会自动重启该服务。
    • START_REDELIVER_INTENT:使用这个返回值时,如果在执行完onStartCommand后,Service被异常kill掉,系统会自动重启该Service,并将Intent的值传入。
    • START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证Service被kill后一定能重启。

其它的还有IntentService的应用,以及混合模式Service就不细说了,只是为了处理某些特殊情况,使用方式基本差不多。

Part Two:优化播放

  1. 创建Service
    在包名上点击右键,依次选择new -> Service -> Service,然后按自己喜好写名字,比如MusicService,最后点finish。
    此时,IDE工具可以帮我们自动在androidManifest.xml完成注册,并继承Service父类。
    将onBind方法的返回值改为null,且重写onCreate方法
  2. 复制代码
    把之前播放背景音乐的代码复制过来
public class MusicService extends Service {
    private MediaPlayer mediaPlayer;

    public MusicService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        AssetFileDescriptor fileDescriptor = getAssetFileDescriptor();
        playBGM(fileDescriptor);
    }


    @Nullable
    private AssetFileDescriptor getAssetFileDescriptor() {
        AssetManager assetManager = getAssets();
        AssetFileDescriptor fileDescriptor = null;
        try {
            fileDescriptor = assetManager.openFd("Westlife - Beautiful in white.mp3");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileDescriptor;
    }

    private void playBGM(AssetFileDescriptor fileDescriptor) {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
            mediaPlayer.setLooping(true);
            mediaPlayer.prepareAsync();
            mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaPlayer.start();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 在MainActivi里启动Service
    private void startMusicService() {
        Intent intent = new Intent(this, MusicService.class);
        startService(intent);
    }

你可能感兴趣的:(MediaPlayer播放背景音乐(二))