Android 进阶——Framework 核心四大组件之常驻后台Service 核心知识总结

引言

Service(服务)是一种可以在后台执行长时间运行操作而没有用户界面的组件,如非特意指定,属于App进程的一部分代码,默认在主线程中创建并运行于主线程,由AMS去通知App去调用Service的生命周期函数。

一、Service的生命周期

在这里插入图片描述

方法 说明
onCreate() 首次创建服务时,系统将调用此方法。若服务已在运行,则不会调用此方法(只处触发一次)
onStartCommand() 当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。
onDestroy() 当服务不再使用且将被销毁时,系统将调用此方法。
onBind() 当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法。
onUnbind() 当另一个组件通过调用unbindService()与服务解绑时,系统将调用此方法。
onRebind() 当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,系统将调用此方法。
  • onCreate()——如果service没被创建过,调用startService()后会执行onCreate()回调;如果service已处于运行中,调用startService()不会执行onCreate()方法。即onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。
  • onStartComand()——服务启动时调用,此方法适合完成一些数据加载工作,比如会在此处创建一个线程用于下载数据或播放音乐。
  • onBind()——服务被绑定时调用。
  • onUnBind()——服务被解绑时调用。
  • onDestroy()——服务停止时调用。

二、Service的声明

和其他四大组件一样,必须在清单文件中声明,原因是PMS需要从清单文件中解析出Service 并为其定义对应的数据结构。

三、Service的启动

Service 可通过两种方式启动:startServicebindService

1、startService启动

通过 startService() 启动 Service 会执行 onCreate()——>onStartCommand()——>onDestroy() 方法。但在 startService(Intent intent) 后,之后只执行一次 onCreate() 方法,反复多次调用 startService 后,Service 只会重复执行 onStartCommand——> onStart(已经过时) 方法,Service 停止后只执行一次 onDestroy 方法。通过这种方式启动 Service ,这个时候的 Service 几乎和 Activity 不能交互(不考虑全局变量的方式),在 Service 里面也没有 getIntent() 方法,完全与其他四大组件隔离且会一直运行下去,直到stopSelf()或者stopService被调用。

1.1、启动Service服务

  • 单次——startService() —> onCreate() —> onStartCommand()

  • 多次——startService() —> onCreate() —> onStartCommand() —> onStartCommand()

1.2、停止Service服务

stopService() —> onDestroy()

startService()通过这种方式调用startService,onCreate()只会被调用一次,多次调用startSercie会多次执行onStartCommand()和onStart()方法,如果外部没有调用stopService()或stopSelf()方法,service会一直运行。而bindService()方式启动,若该服务之前还没创建,系统回调顺序为onCreate()→onBind(),如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法不会多次创建服务及绑定。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,回调顺序为onUnbind()→onDestroy()。

2、bindService 启动服务(Binder机制实现)

bindService(Intent intent ,ServiceConnection connetion,int flag)来启动 Service,相当于 Service和Context 绑定到一起, Service 启动的生命周期是:onCreate——>onBind(iBnder 会作为参数传递到 connect 中的 onServiceConnected 方法中),绑定后再次执行 bindService Service 什么都不执行。如果 Context 销毁了,则Service将会被销毁,执行 onUnbind -> onDestroy。

2.1、绑定Service服务

bindService() —> onCreate() —> onBind()

2.2、解绑Service服务

unbindService() —> onUnbind() —> onDestroy()

2.3、启动绑定Service服务

startService() —> onCreate() —> onStartCommand() —> bindService() —> onBind()

2.4、解绑停止Service服务

unbindService() —> onUnbind() —> stopService() —> onDestroy()

2.5、解绑绑定Service服务

unbindService() —> onUnbind(ture) —> bindService() —> onRebind()

四、如何保证Service不被杀死 ?

1、onStartCommand方式中,返回START_STICKY或则START_REDELIVER_INTENT

  • START_STICKY——如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象

  • START_NOT_STICKY——如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service

  • START_REDELIVER_INTENT——如果返回START_REDELIVER_INTENT,其返回情况与START_STICKY类似,但不同的是系统会保留最后一次传入onStartCommand方法中的Intent再次保留
    下来并再次传入到重新创建后的Service的onStartCommand方法中

2、提高Service的优先级 在AndroidManifest.xml文件中对于intent-filter可以配置android:priority

这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

3、在onDestroy方法里重启Service

当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service;

4、提升Service进程的优先级

进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程 ,可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些。

5、将APK安装到/system/app,变身为系统级应用

五、Service的类别

  • 前台服务 foreground service ——通过startForegroundService 方法启动,提供一些可感知的操作,优先级比普通服务高些,耗时超过ActivityService#SERVICE_TIMEOUT(即20s)则ANR。

  • 后台服务 background service——通过startService 启动,执行的操作对用户而言是不可感知的,耗时超过ActivityService#SERVICE_BACKGROUND_TIMEOUT(即200s)则ANR。

  • 绑定服务 bound service——通过bindService启动,主要是提供c/s接口,允许组件与service进行通信或者是跨进程的通信。

前后台服务本质上执行的方法是一致的,区别在于传入的一个标记值,requireForeground,即一个boolean形的标志位决定是bg还是fg service。

六、IntentService

IntentService继承于Service, 它的实现相当于在Service的基础上增加了一个HandlerThread, 以及自定义的Handler, IntentService将所有的耗时操作放到HandlerThread线程中去处理, 当onHandleIntent处理完后,就会调用stopSelf来停止到这个Service,所以每次启动一个IntentService, 都是经过这样的生命周期 onCreate -> onStartCommand -> onStart -> onHandleIntent -> onDestroy,其中onStart/onStartCommand都将Intent route到了onHandleIntent中去处理。

public class MyIntentService extends IntentService {

    public static UpdateUI updateUI;
    public static void setUpdateUI(UpdateUI updateUIInterface){
        updateUI=updateUIInterface;
    }

    @Override
    protected void onHandleIntent(Intent intent) {
      //在子线程中进行网络请求
        Bitmap bitmap=downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
        Message msg1 = new Message();
        msg1.what = intent.getIntExtra(INDEX_FLAG,0);
        msg1.obj =bitmap;
        //通知主线程去更新UI
        if(updateUI!=null){
            updateUI.updateUI(msg1);//通过Handler将msg1发送到主线程更新UI
        }
    }
    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }
    public interface UpdateUI{
        void updateUI(Message message);
    }

    private Bitmap downloadUrlBitmap(String urlString) {
        ....
        return bitmap;
    }
}

应用

public class IntentServiceActivity extends Activity implements MyIntentService.UpdateUI{
    private String url[] = {..};
    private static final Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            imageView.setImageBitmap((Bitmap) msg.obj);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_intent_service);
        imageView = findViewById(R.id.image);
        Intent intent = new Intent(this,MyIntentService.class);
        for (int i=0;i<url.length;i++) {
            intent.putExtra(MyIntentService.DOWNLOAD_URL,url[i]);
            intent.putExtra(MyIntentService.INDEX_FLAG,i);
            startService(intent);
        }
        MyIntentService.setUpdateUI(this);
    }

    @Override
    public void updateUI(Message message) {
        mUIHandler.sendMessageDelayed(message,message.what * 1000);
    }

七、Service 和IntentService

Service是用于后台服务的,当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念。Service既不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,因此不宜在Service中编写耗时的逻辑和操作,否则可能导致会引起ANR。为了解决这样的问题,引入了IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期。那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行耗时操作IntentService,异步处理服务,新开一个线程,handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务,再通过Handler 与主线程通信

未完待续…

猜你喜欢

转载自blog.csdn.net/CrazyMo_/article/details/105871356