Android

Android四大组件之Service

2019-03-19  本文已影响40人  12313凯皇

一、概述

ServiceAndroid四大组件之一,是一个计算型组件。它在Android开发中扮演着一个重要的角色,虽然他不如Activity那么常见,但是在很多App中都有着实际的应用场景。
Service的运行不依赖于任何用户界面,所以它非常适合用于去执行那些不需要和用户交互但却需要长期运行的任务,如App的更新,音乐播放器等。

二、生命周期

官方文档提供的Service生命周期图如下:


由图中可知Service两种启动方法,其中共涉及了5个回调方法

三、启动方式

上面已经说过了,Service启动方式有两种

  1. 通过Context.startService()方法启动一个Service,并回调服务中的onStartCommand()方法。如果该服务之前还没被创建过,那么回调的顺序为:onCreate()->onStartCommand()。服务启动后会一直保持运行状态,直到stopService()stopSelf()方法被调用,服务停止并回调onDestory()。另外,无论调用多少次startService()方法,只需调用一次stopService()stopSelf()方法,服务就停止了。
  2. 通过Context.bindService()绑定一个Service,并回调服务中的onBind()方法,同样的如果是第一次创建则会先调用onCreate()方法。之后,调用方法可以获取到onBind()方法里返回IBinder对象的实例,从而实现和服务进行通信。只要调用方与服务之间的连接没有断开,服务就一直保持运行状态,直到调用unbindService()方法服务才会停止,回调顺序onUnBind() -> onDestory()

尽管Service组件是用于执行后台计算的,但是它本身是运行在主线程中的,所以耗时的后台计算仍然需要在单独的线程中完成。但是处于这种状态时,外界可以很方便的和Service组件进行通信。

区别startService()开启服务后便于Activity没有关联了,即不受影响,独立运行;而bindService()开启服务后与Activity仍存在关联,退出Activity时必须调用unBindService方法,否则会报ServiceConnection泄漏的错误。

注意:这两种启动方式并不冲突,当使用Context.startService()启动服务后仍可以再用bindService()方法绑定服务,但是需要同时调用stopService()onUnBind()方法才能停止服务。

四、基本用法

Service其实有三种类型:普通Service、前台Service和系统Service。
前台Service就是利用Notification然后调用startForeground方法以通知的形式将Service显示出来。
系统Service,顾名思义就是系统的一些服务了,常见的系统服务有:


通过getSystemService方法传入name值即可得到相应的服务对象。

普通Service对于我们而言应用场景就比较广泛了,下面将使用一个音乐播放器的小Demo来展示如何注册并使用一个普通广播:

  1. 首先我们需要实现MusicService并继承Service这个类,以提供播放、暂停和停止音乐的方法:
public class MusicService extends Service {

    private final String TAG = "MusicService";

    private MediaPlayer mediaPlayer;

    private int startId;

    //枚举类型 标记播放状态
    public enum Control {
        PLAY, PAUSE, STOP
    }

    public MusicService() {
    }

    @Override
    public void onCreate() {
        if (mediaPlayer == null) {
            //创建MediaPlayer对象  R.raw.my_music为mp3格式资源文件夹中的音乐
            mediaPlayer = MediaPlayer.create(this, R.raw.my_music);
            mediaPlayer.setLooping(false);  //是否单曲循环
        }
        Log.d(TAG, "onCreate: ");
        super.onCreate();
    }


    //使用startService方法启动Service的一个生命周期方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.startId = startId;
        Log.d(TAG, "onStartCommand: ---------startId=" + startId);
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            Control control = (Control) bundle.getSerializable("Key");
            if (control != null) {
                switch (control) {
                    case PLAY:
                        play();
                        break;
                    case PAUSE:
                        pause();
                        break;
                    case STOP:
                        stop();
                        break;
                }
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    //继承Service必须实现的一个方法
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return null;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();  //释放资源
        }
        super.onDestroy();
    }

    private void play() {
        if (!mediaPlayer.isPlaying()) {
            mediaPlayer.start();
        }
    }

    private void pause() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
        }
    }

    private void stop() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.stop();
        }
        stopSelf(startId);  //停止服务
    }

}
  1. AndroidManifest.xml中注册Service
 <!--添加label标签以便在系统中识别-->
<service 
     android:name=".MusicService" 
     android:label="@string/app_name" />
  1. 在布局文件中添加三个按钮分别控制音乐播放器的状态,这里就不展示xml文件中的布局代码了,直接看Activity里的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button playButton = findViewById(R.id.btn_play);
        playButton.setOnClickListener(this);
        Button pauseButton = findViewById(R.id.btn_pause);
        pauseButton.setOnClickListener(this);
        Button stopButton = findViewById(R.id.btn_stop);
        stopButton.setOnClickListener(this);
    }

    //播放音乐
    public void playMusic(View view) {
        Intent intent = new Intent(this, MusicService.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("Key", MusicService.Control.PLAY);
        intent.putExtras(bundle);
        startService(intent);
    }

    //暂停音乐
    public void pauseMusic(View view) {
        Intent intent = new Intent(this, MusicService.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("Key", MusicService.Control.PAUSE);
        intent.putExtras(bundle);
        startService(intent);
    }

    //停止音乐
    public void stopMusic(View view) {
        Intent intent = new Intent(this, MusicService.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable("Key", MusicService.Control.STOP);
        intent.putExtras(bundle);
        startService(intent);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_play:
                playMusic(v);
                break;
            case R.id.btn_pause:
                pauseMusic(v);
                break;
            case R.id.btn_stop:
                stopMusic(v);
                break;
        }
    }
}

Demo效果截屏:



log输出:


根据测试可以得出结论:只有第一次启动服务时才会执行onCreate()方法,之后再次启动则只会调用onStartCommand()方法,且每次启动Service都会有一个startId用于唯一标识每次对Service发起的处理请求。调用stopSelf()方法后会回调onDestroy()方法,之后服务被终止。

五、IntentService

IntentService继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统的Service一样,同时,当执行完后,IntentService会自动停止,而不需要我们手动去控制或stopSelf()
由于大多数启动服务都不必同时处理多个请求(像上一个Demo中Service就处理了多个请求),因此使用IntentService类实现服务也许是最好的选择。IntentService内部采用了HandlerThread,所以某种程度上也可以把它当成是一个特殊的线程,有关它的更多信息可以到我的另一篇文章中Android的线程和线程池了解。

参考文章:Android Service使用详解学习笔记| AS入门(十) 组件篇之Service

上一篇下一篇

猜你喜欢

热点阅读