美文网首页
Service的使用

Service的使用

作者: 笔墨Android | 来源:发表于2018-01-23 09:35 被阅读0次

    不怕跌倒,所以飞翔

    本文讲解内容:

    • Service的简单使用
      • 普通Service
      • IntentService
    • Service的绑定操作
    • Service的生命周期
    • 前台Service的使用
    • Android通知栏的使用

    1.Service的简单使用

    1.1普通Service的简单使用

    后台服务的优先级是很低的,当系统内存不足的时候就会被回收.

    • 创建Service
    • 重写相应的方法
    • 启动/关闭服务

    1.1.1 创建服务

    创建服务的方法就不写了,这里主要说 明一下AndroidManifest中的属性

    • android:name Service的类名称
    • android:label Service的名字
    • android:icon Service的图标
    • android:enabled 是否可以被系统实例化,默认是true 因为父标签也有enable属性,所以必须两个都为true的情况下服务才能被激活,否则不会被激活.
    • android:exported 代表是否能被其他应用隐式调用,由inter-filter决定,如果为false的情况下,即便你匹配了inter-filter也无法隐式调用
    • android:process 是否需要在单独的进程中运行,当设置为android:process = ":remote"时,代表Service在单独的进程中运行.这里注意":"很重要,它的意思是要在当前进程名称前面附加上当前的包名,所以"remote"和":remote"不是同一个意思,前者的进程名称为:remote,而后者的进程名称为: App-packageName:remote.
    • android:permission 是权限声明
    • android:isolatedProcess 设置true意味着服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限.与其通信的唯一途径就是通过服务的API(bind and start)

    1.1.2重写相应的方法

    public class GeneralService extends Service {
        private String TAG = GeneralService.class.getSimpleName();
    
        public GeneralService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            /*这个是绑定Binder的相应的方法,
              *这个服务中先不去考虑
              */
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            /*
            * 创建服务的时候调的回调
            * 这个方法只有在创建Service的时候执行一次
            */
            Log.e(TAG, "服务创建了");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            /*
            * 具体执行逻辑的时候的方法
            * 1.这里有一点问题说明一下,有的时候你创建相应的服务了,但是由于后台资源不足,服务被销毁了
            * 这个时候,在执行的时候就会存在相应intent为空的情况,当你遇到这个情况的时候,只要返回相应的标识就可以了
            *  return Service.START_REDELIVER_INTENT;就能保证服务再次启动的时候intent不为空了
            * 2.这个方法每次调用相应的startService都会去执行
            */
            Log.e(TAG, "服务正在执行");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            /*
            * 销毁服务的回调
            * 这个方法只有在销毁Service的时候执行一次
            */
            Log.e(TAG, "服务销毁了");
        }
    }
    

    1.1.3启动/关闭服务

    • 开启服务
          Intent intent = new Intent(this, GeneralService.class);
          startService(intent);
      
    • 关闭服务
          Intent intent = new Intent(this, GeneralService.class);
          stopService(intent);
      

    1.1.4这里着重介绍一下相应得方法

    • onCreate 服务创建的时候回调的方法
    • onBind 绑定服务的时候调用的方法,后面将服务绑定的时候讲解
    • onStartCommand 执行逻辑的方法
    • onDestory 服务关闭时候的回调方法

    相应的执行逻辑:

    1. 正常的生命周期逻辑(第一次启动)
      构造方法()->onCreate()->onStartCommand()->onDestory();
    2. 当Service存在的情况下再次启动
      onStartCommand()

    也就是说如果多次点击启动,onCreate()不会多次执行,只有Service销毁的时候再次启动的时候才会执行相应的onCreat()方法,简单理解就是onCreat()方法只有在创建的时候执行一次!

    1.2IntentService的简单使用

    使用上和上面的内容没有什么出入,只是继承的方法和内部相应的实现有点变化,但是变化不是很大,这里就贴一下相应的内容,不去做相应的具体讲解了,只要记住这个Service能自己调用相应的onDestory()就可以了.

    public class IntentService extends android.app.IntentService {
        private String TAG = IntentService.class.getSimpleName();
    
        public IntentService() {
            super("IntentService");
            /*调用父类的构造方法,这里面传入的名字是工作线程的名称,所以这个名称你可以随便传*/
            Log.e(TAG, "服务有名字了");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.e(TAG, "服务创建了");
        }
    
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            /*
             * 在我的理解,这个工作线程只会有一个,因为里面维护了一个相应的Handler
             * 每次的耗时操作都会以相应的队列的方式在IntentService中一次执行
             * 每次开启服务的时候都会走这个方法,但是我调用相应的Stop无法停止相应的服务
             * 这个还有待于研究,因为子停止,或许不需要停止的相应的方法吧(反正相应的停止的方法是不好使的)
             */
            for (int i = 0; i < 100; i++) {
                Log.e(TAG, "服务正在执行" + i);
            }
        }
    
        @Override
        public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
            /*这个方法实在o'nHandleIntent之前进行执行
              *所以这里可以初始化一些相应的内容
              */
            Log.e(TAG, "onStartCommand: 执行了");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            /*这个方法会在相应的onHandleIntent执行完成的时候回调*/
            Log.e(TAG, "服务销毁了");
        }
    }
    

    相应的启动方法类似.

    但是这里要注意几个问题:

    1. 当你startService的时候,即使你调用相应的stopService也不会让Service停止下来
    2. 这个服务不存在相应的stopService的方法了

    剩下的基本上注释都有.

    2.绑定服务的方法

    • 简单的介绍一下为什么要绑定服务

    你可能会发现,上面的方法只是启动了服务,但是其实Service和Activity其实根本没有什么关联,在Activity也没有办法去控制Service里面的执行内容,也就是Service脱离了相应的Activity,只是通过Activity启动而已,这个不是我们想看到的,所以才有相应的绑定方法来控制Service.

    2.1 绑定服务的写法

    上面在开启服务的时候,不知道大家有没有注意到一个细节在onBind()方法中我们返回的是空,为什么这里返回的是空呢???其实这个就是绑定服务所要必须的内容.下面我们开始实现简单的内容吧!

    2.1.1创建相应的Binder对象

        class MyBinder extends Binder {
            public void startBinder() {
                Log.e(TAG, "startBinder: ");
            }
    
            public void stopBinder() {
                Log.e(TAG, "stopBinder: ");
            }
        }
    

    这里面的方法你可以随便的写,想要什么写什么!!!

    2.1.2在相应的Service中创建相应的对象,并在Binder()中返回

        private MyBinder mMyBinder = new MyBinder();
    
        @Override
        public IBinder onBind(Intent intent) {
            return mMyBinder;
        }
    

    2.1.3启动相应的Service

    这个也是这里的重点问题,涉及到一个ServiceConnection

        private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                /*这个方法会在相应的创建的时候进行调用*/
                Log.e(TAG, "onServiceConnected:  连接创建的时候调用");
                //向下转型从而调用相应的方法
                BindService.MyBinder binder = (BindService.MyBinder) service;
                binder.bindService();
         }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
               /*这个方法是在Service丢失的情况下才被调用
                * 或者在Service被杀死的视乎调用*/
            }
        };
    

    说明一下上面两个回调方法:

    • onServiceConnected 系统调用这个方法来传送在Service的onBind中返回的IBinder
    • onServiceDisconnected 在Service的链接意外丢失的时候调用这个方法,比如当Service崩溃了或者被越塔强杀了的时候会调用这个方法,但是注意当解除绑定的时候不会调用这个方法.
    • 还有一点说明一下:startBinder()这个方法是你自己的方法,也就是说,在这里你就可以控制Service了
         //绑定
            Intent intent = new Intent(this, BindService.class);
            /*参数三有必要说明下:
             *BIND_AUTO_CREATE 这个方法是创建关联后自动创建Service,会使得相应Service中的onCreate()方法的到执行
             * 但相应的onStartCommand()不会被执行
             */
            bindService(intent, mConnection, BIND_AUTO_CREATE);
       
         //解绑
            unbindService(mConnection);
    

    2.1.3BindService的生命周期

    构造方法->oncreate()->onBind()->onServiceConnected()
    当你再次点击的时候不会调用相应的启动的流程了,除非你调用unBind()方法进行相应的取消否则不会去创建的,这里只是创建了连接,让Activity持有了相应的Service可以使用内部的相应方法了!

    3.Service的声明周期

    • 当你调用startService()的时候生命周期是这样的:
      onCreate() -> onStartCommand()
      这里注意,要是之前你启动过这个service的话那么onCreate()不会多次调用,除非你调用了** stopService(mIntent);**结束了这个Service否则不会在走onCreate();也就是说生命周期中onCreate()只会执行一次;
    • 当你调用stopService()的时候生命周期是这样的:
      onDestroy()
    • 当你调用bindService的时候和上面的生命周期类似,这里只是建立了一个持久连接.别无其他.
    • boolean onUnBind(Intent intent) 当该Service上绑定得所有客户端都断开连接得时候回调

    这里有一个问题是你需要注意的,如果你想在onStartCommand()想结束Service的话,直接调用stopSelf()方法就可以了

    3.1几种特殊情况下的生命周期问题

    • 当一个Service既被调用了bindService()又调用了startService(),这种情况下你如果想要关闭服务的话,必须两种服务的结束方法都调用才能结束当前的服务.也就是stopService()和unBindService()方法同时执行,这样Service才会走onDestroy()方法.

    4.一些服务的特殊使用方法

    开机启动服务(其实这个思路很简单,监听开机的广播,然后启动你的服务就可以实现了),下面直接上代码:

    • 广播的代码:
    public class BootBroadcastReceiver extends BroadcastReceiver {
        private static final String mBootAction = "android.intent.action.BOOT_COMPLETED";
        private static final String mShutDownAction = "android.intent.action.ACTION_SHUTDOWN";
        private static final String TAG = BootBroadcastReceiver.class.getSimpleName();
        private Intent mServiceIntent;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent == null) return;
            if (intent.getAction().equals(mBootAction)) {
                Log.e(TAG, "onReceive: 监听到开机广播了");
    
                /*这里启动服务*/
                mServiceIntent = new Intent(context, MyService.class);
                mServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startService(mServiceIntent);
    
            } else if (intent.getAction().equals(mShutDownAction)) {
                Log.e(TAG, "onReceive: 监听到关机广播了");
                if (mServiceIntent != null) {
                    /*这里关闭服务*/
                    context.stopService(mServiceIntent);
                }
            }
        }
    }
    
    • 广播在清单文件中注册的代码
            <receiver
                android:name=".BootBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <!--开机广播-->
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
                <!--关机广播-->
                <intent-filter>
                    <action android:name="android.intent.action.ACTION_SHUTDOWN"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </receiver>
    

    其实上面的内容加起来就可以启动相应的广播了,但是一定要注意一点就是监听开机广播的时候涉及到权限的问题

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    

    这个问题千万别忘了...

    相关文章

      网友评论

          本文标题:Service的使用

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