Service的使用

不怕跌倒,所以飞翔

本文讲解内容:

  • 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" />

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容