Android 四大组件--service的使用与生命周期

1. 什么是服务(service)

官方给出的解释:
A Service is an application component that can perform long-running operations in the background, and it doesn’t provide a user interface. Another application component can start a service, and it continues to run in the background even if the user switches to another application

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。要注意的是服务默认在应用程序的主线程中运行,如果要在服务中进行耗时操作,建议使用 IntentService。

2. 基本使用

启动 service 的方法有两种,一种是 startService(),一种是 bindService()。不同的启动方式有不同的生命周期。
service 生命周期

2.1 startService()

这种方式比较简单,在 AndroidManifest.xml 文件中注册后就可启动

// 启动服务
startService(Intent(this, ComponentService::class.java))

// 结束服务
stopService(Intent(this, ComponentService::class.java))

开启服务时,Service 会调用 onCreate() 方法,然后在调用 onStartCommand() ,多次调用 startService() 启动统一服务,该服务只会调用一次 onCreate() 方法,之后再调用直接执行 onStartCommand() ,如果想结束服务,调用 stopService() 或者在 Service 中调用 stopSelf() 即可。如果不调用,该服务会一直存在,直到应用结束,或者内存不足被回收。

2.2 bindService()

绑定服务

val conn = object:ServiceConnection{
        override fun onServiceDisconnected(name: ComponentName?) {
        //只有当我们自己写的MyService的onBind方法返回值不为null时,才会被调用
            Log.i(TAG, "onServiceDisconnected")
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        //这个方法只有出现异常时才会调用,服务器正常退出不会调用。
           // (service as ComponentService.MyBinder).print()
            Log.i(TAG, "onServiceConnected")
        }
    }
  // 绑定服务
bindService(Intent(this,ComponentService::class.java),conn, Context.BIND_AUTO_CREATE)

解绑服务

unbindService(conn)

被绑定了的服务,一定要解绑,如果在 activity 中绑定,在退出 activity 时没有解绑,会造成内存泄漏。

E/ActivityThread: Activity lxy.com.kotlinandroid.component.Component2Activity has leaked ServiceConnection lxy.com.kotlinandroid.component.Component2Activity$conn$1@62f65fb that was originally bound here
                  android.app.ServiceConnectionLeaked: Activity lxy.com.kotlinandroid.component.Component2Activity has leaked ServiceConnection lxy.com.kotlinandroid.component.Component2Activity$conn$1@62f65fb that was originally bound here

同时,unbindService() 只能调用一次,多次调用会报错。

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: lxy.com.kotlinandroid, PID: 16281
                  java.lang.IllegalArgumentException: Service not registered: lxy.com.kotlinandroid.component.Component2Activity$conn$1@e631618

总结一下,通过 bindService() 启动的服务,生命周期为 onStart() => onBind() => onUnbind() —> onDestroy()。需要注意的是关闭服务需要 stopService 和 unbindService 都被调用,没有先后顺序的影响,只调用其中一个方法,onDestory() 都不会执行,服务也不会被关闭。

同时要注意的是 service 运行并不是单独的一个进程或线程,它是运行在主线程中的,所以尽可能的不在service 中进行耗时操作,否则会引起 ANR (前台服务20s,后台服务200s)。如果实在要在 service 中进行耗时操作的话,可以使用 IntentService 。

IntentService

IntentService 继承 Service,与至不同的是 IntentService 在创建之后会另起一个线程,耗时操作可以运行在该线程中。其实主要是继承一个方法:

    override fun onHandleIntent(intent: Intent?) {
		// 执行耗时操作
    }

那么为什么 IntentService 不用担心 ANR 问题呢?这个可以去源码里面找答案。

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null.
     * @see android.app.Service#onBind
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     *               This may be null if the service is being restarted after
     *               its process has gone away; see
     *               {@link android.app.Service#onStartCommand}
     *               for details.
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

通过源码可以看出,在 onCreate() 方法中开启了一个线程,同时初始化了一个 handler ,在 onStartCommand() 方法中调用 onStart() 使用 handler 发送一个无延迟的消息,然后调用了我们实现的 onHandleIntent() 方法,执行耗时操作,所以不用担心 ANR。

注意,IntentService 在处理完所有启动请求后停止服务,因此不必调用 stopSelf()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值