美文网首页
Android Service

Android Service

作者: 日三省 | 来源:发表于2016-07-25 22:11 被阅读302次

    Service,能成为Android四大组件之一,它的重要性就不言而喻了。

    先说要讲什么:

    • Service的使用
    • Service的生命周期
    • Service运行在什么线程
    • 对Service的理解

    Service的使用

    作为四大组件之一,使用前肯定需要在AndroidManifest.xml中注册。

    <service android:name=".service.MyIntentService" />
    <service android:name=".service.NormalService" />
    

    创建类并继承android.app.Service

    public class NormalService extends Service {
    
        final String TAG = "Service";
    
        MyBinder myBinder = new MyBinder();
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            LogTool.e(TAG, "Service Thread --> " + Thread.currentThread().getName());
            LogTool.e(TAG, "----- onCreate -----");
        }
    
        @Override
        public void onDestroy() {
            LogTool.e(TAG, "----- onDestroy -----");
            super.onDestroy();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            LogTool.e(TAG, "----- onStartCommand -----");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onRebind(Intent intent) {
            LogTool.e(TAG, "----- onRebind -----");
            super.onRebind(intent);
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            LogTool.e(TAG, "----- onUnbind -----");
            return super.onUnbind(intent);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            LogTool.e(TAG, "----- onBind -----");
            return myBinder;
        }
    
        class MyBinder extends Binder {
    
            public void doSth() {
                LogTool.e(TAG, "-----Binder  doSth -----");
                LogTool.e(TAG, "Binder Thread --> " + Thread.currentThread().getName());
            }
        }
    }
    

    没有复杂的逻辑,基本上是继承父类方法,然后打印相应log。

    两种方式使用Service:

    //启动一个Service
    Intent intent = new Intent(this, NormalService.class);
    startService(intent);
    //停止一个Service
    Intent intent = new Intent(this, NormalService.class);
    stopService(intent);
    
    //以“绑定”的方式启动一个Service
    //mServiceConnection对象稍后再谈
    Intent intent = new Intent(this, NormalService.class);
    bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    //解除绑定
    unbindService(mServiceConnection);
    

    Service的生命周期

    先不看线程信息,通过startService开启一个服务,它的生命周期是这样的:

     E/Service: ----- onCreate -----
     E/Service: ----- onStartCommand -----
    

    这时,一个服务已经创建了。如果再次执行startService,开启同一个服务,onStartCommand方法被再次调用,而onCreate只在Service第一次被创建时调用。

    E/Service: ----- onStartCommand -----
    

    通过stopService结束一个服务

    E/Service: ----- onDestroy -----
    

    通过bindService开启一个服务

    bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
    

    mServiceConnection是用来维护Activity与Service之间的联系。

    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogTool.e(TAG, "----- onServiceConnected -----");
            myBinder = (NormalService.MyBinder) service;
            myBinder.doSth();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            LogTool.e(TAG, "----- onServiceDisconnected -----");
        }
    };
    

    绑定是异步的,IBinder对象只能从onServiceConnected方法中获得。
    BIND_AUTO_CREATE是最常用的flag,它表示在service不存在时就创建一个,还有其他几种标识可供选择。通过bindService开启一个Service,它的生命周期是这样的:

    E/Service: ----- onCreate -----
    E/Service: ----- onBind -----
    E/Service: ----- onServiceConnected -----
    

    Service创建后,再次bindService

    E/Service: ----- onBind -----
    

    解除绑定或者绑定的activity返回

    E/Service: ----- onUnbind -----
    E/Service: ----- onDestroy -----
    

    如果两种启动Service的方式同时用,会有什么效果呢?

    startService --> bindService --> stopService --> unbindService

    //startService 
    E/Service: ----- onCreate -----
    E/Service: ----- onStartCommand -----
    //bindService
    E/Service: ----- onBind -----
    E/Service: ----- onServiceConnected -----
    //stopService什么也没打印
    //unbindService
    E/Service: ----- onUnbind -----
    E/Service: ----- onDestroy -----
    

    startService --> bindService -->unbindService --> stopService

    //startService 
    E/Service: ----- onCreate -----
    E/Service: ----- onStartCommand -----
    //bindService
    E/Service: ----- onBind -----
    E/Service: ----- onServiceConnected -----
    //unbindService
    E/Service: ----- onUnbind -----
    //stopService
    E/Service: ----- onDestroy -----
    

    startService和bindService的先后顺序不影响最终结果。

    把Service看做一个对象,startService和bindService就好比这个对象的两个强引用,onDestroy是系统回收Service对象内存的操作,onUnbind是bindService这种引用所特有的、在回收内存之前必须做的准备工作。

    当只有startService这种引用时,调用stopService后,不需要准备工作,Service直接被回收;当只有bindService这种引用时,调用unbindService,回收工作分两步走:第一,准备工作。第二,才是回收内存。

    当一个Service对象同时拥有这两种引用时的逻辑也就容易理解了吧。

    Service运行在什么线程

    startService --> stopService --> bindService -->unbindService

    //startService方式
    E/Service: Service Thread --> main
    E/Service: ----- onCreate -----
    E/Service: ----- onStartCommand -----
    E/Service: ----- onDestroy -----
    //bindService方式
    E/Service: Service Thread --> main
    E/Service: ----- onCreate -----
    E/Service: ----- onBind -----
    E/Service: ----- onServiceConnected -----
    E/Service: -----Binder  doSth -----
    E/Service: Binder Thread --> main
    E/Service: ----- onUnbind -----
    E/Service: ----- onDestroy -----
    

    默认情况下,service代码是运行在UI线程的,所以耗时操作需要开启子线程。
    这里介绍一个封装好的Service类。

    /**
     * 调用方式与传统Service相同
     * 每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行
     * 不会阻塞UI线程
     * 任务执行完毕,自动结束
     * 默认实现的onStartCommand()的目的是将intent插入到工作队列中
     */
    public class MyIntentService extends IntentService {
    
        final String TAG = "Service";
    
        public MyIntentService() {
            super("MyIntentService");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return super.onBind(intent);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            LogTool.e(TAG, "MyIntentService onCreate Thread --> " + Thread.currentThread().getName());
            LogTool.e(TAG, "----- onCreate -----");
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            LogTool.e(TAG, "----- onDestroy -----");
        }
    
        //    处理一下耗时任务
        @Override
        protected void onHandleIntent(Intent intent) {
    
            LogTool.e(TAG, "MyIntentService onHandleIntent Thread --> " + Thread.currentThread().getName());
            LogTool.e(TAG, "----- onHandleIntent -----");
    
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void onStart(Intent intent, int startId) {
            super.onStart(intent, startId);
            LogTool.e(TAG, "----- onStart -----");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            LogTool.e(TAG, "----- onStartCommand -----");
            return super.onStartCommand(intent, flags, startId);
        }
    }
    

    startService

    E/Service: MyIntentService onCreate Thread --> main
    E/Service: ----- onCreate -----
    E/Service: ----- onStartCommand -----
    E/Service: ----- onStart -----
    E/Service: MyIntentService onHandleIntent Thread --> IntentService[MyIntentService]
    E/Service: ----- onHandleIntent -----
    //6秒钟之后onDestroy,因为sleep了6000毫秒
    E/Service: ----- onDestroy -----
    

    so,onHandleIntent 是可以执行耗时操作的。

    对Service的理解

    1. 如何理解activity在前台,service在后台?
      个人认为,这里的“前”和“后”指的是,是否有一个可视的界面作为依托。
    2. service默认运行在主线程,那它又有什么卵用呢?
      如果要做一个音乐播放器,难道把播放音乐的逻辑放在某个activity里么?activity被销毁了,音乐就停了?这时候就非常需要一个不依靠界面而存在东西,而且,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。那感觉就像“你看得见,或看不见它,它就在那里”。

    相关文章

      网友评论

          本文标题:Android Service

          本文链接:https://www.haomeiwen.com/subject/wbmgjttx.html