service&广播那些事儿

一切的学习从基础学习,那么Android复习的方式也是,先从四大组件着手,然后就是面试重点的Handler机制,View的绘制流程,事件分发机制,优化方法,EventBus源码解析,Okhttp源码解析,底层了解Activity的绘制流程等等.这也是后续的大致内容趋势,在回顾中笔记,在笔记中巩固.

服务

startService&bindService

service启动的方式有两种,一种是startService的方式,一种是bindService的方式,两者在使用上也是有区分,那么我们来好好了解一番.

startService

生命周期
  • onCreate()
    首次创建时,系统会调用此方法,去设置程序.
  • onStartCommand()
    当调用startService的时候,会调用此方法.
  • onDestroy()
    当服务不在执行,被销毁的时候调用此方法.
基本使用

通过startService去启动服务,stopService去停止服务.

bindService

生命周期
  • onCreate()
    首次创建时,系统会调用此方法,去设置程序.
  • onBInd()
    当调用bindService的时候,会调用此方法.(但只会执行一次)
  • onUnbind()
    当调用unBIndService的时候,会调用此方法
  • onDestroy()
    当服务不在执行的时候,被销毁执行该方法.
基本使用

通过bindService去绑定服务,通过unbindService去停止服务


基本使用这里不做过多的讲解,主要来讲解service的组合使用这也是面试点之一.

组合使用

那在平时的开发中,我们肯定不止使用一种启动方式,可能会重复调用startService,或者是bindService,再或者是两个交替调用,那么这个时候,生命周期走了哪些?会有哪些影响?
我们依次已不同的步骤去讲解,分析

情况1

第一步:反复调用startService;第二步:再调用stopService
因为onCreate只有在首次创建的时候会被回调,所以onCreate只会出现一次,而onStartCommand方法与startService有关,每调用一次startService都会回调一次.故最终生面周期呈现如下:

  • 第一步:onCreate->onStartCommand…onStartCommand
  • 第二步:onDestory
情况2

第一步:反复调用bindService;第二步:再调用unBindService
onCreate同理,只有在首次被创建的时候,才会被回调.而onBind的回调与bindService调用的时机有关,但是只能回调一次.故最终生面周期如下:

  • 第一步:onCreate->onBind
  • 第二步:onUnBInd->onDestory
情况3

第一步:先调用startService;第二步:调用bindService;第三步:调用stopService;第四步:调用unbindService
我们先来看看四步对应的生面周期

  • 第一步:onCreate()->onStartCommand()
  • 第二步:onbind()
  • 第三步:无响应
  • 第四步:onunbind()->onDestory()

我们可以看到第三步无响应,是不是因为后启动bindService,所以只有unbindService有效你?不妨咱们在换一个顺序.

情况4

第一步:先调用bindService;第二步:调用startService;第三步:调用stopService;第四步:调用unbindService

  • 第一步:onCreate()->onbind()
  • 第二步:onStartCommand()
  • 第三步:无响应
  • 第四步:onunbind()->onDestory()

这就说明了两种启动方式其实是有优先级的,凡是start与bind组合使用的时候,只有unbind可以停止service,stop无法停止.

所以我们可以得出结论

  • 反复调用startService,onstartcommand会被多次回调
  • start与bind组合调用,stop无法结束service,只有unbind
  • start开启的服务,不管调用者是否存在,只有没有stop就一直存在
  • bind开启的服务,当调用者结束生命周期时,service也跟着结束.

IntentService

IntentService也是一种Service,IntentService是Service+HandlerThread的结合.所以就赋予了IntentService的一些特殊性.

  • IntentService内有一个工作线程来处理耗时操作.
  • 当任务执行完后,IntentService会自动停止,不需要我们手动去stop或者是unbind
  • 如果多次启动IntentService,那么每一个耗时操作会以工作队列的形式在IntentService的onHandleIntent回调方法中去执行,依次去执行.

那么我们从源码的角度去分析,为什么IntentService具备这些特殊的特性.

IntentService源码

看源码的顺序,就按照生面周期的顺序去看去学习吧

onCreate
@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);
    }

上诉代码就解释了为什么IntentService可能执行耗时操作.能进行耗时操作必须要在子线程中.子线程哪里来的?在onCreate方法中,通过HandlerThread.start的时候,跑起子线程通过getLooper去获取其子线程的Looper,再通过Handler的构造方法,去创建一个在子线程中的Handler.所以在onCreate中就部署好了子线程的环境.
接下来我们去看看onStart方法

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

我们可以看到,onStart的任务就是将任务添加到mServiceHandler的队列中,mServiceHandler上面也分析了,是在onCreate创建的,是一个跑在子线程的一个handler.但是onStart只会被调用一次,岂不是意味着只能执行一次耗时操作?接下来我们来看看onStartCommand方法

onStartCommand
 @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

我们可以看到,onStartCommand方法中又去调用了onStart方法,我们知道onStartCommand,只可以被多次调用的,所以每一次调用onStartCommand,间接的调用了onStart方法,那么任务就都会被添加到mServiceHandler的队列中.这就解释了IntentService可以按照顺序多次执行耗时任务.

mServiceHandler

接下来我们来看看,mServiceHandler队列到底做了什么

 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);
        }
    }

mServiceHandler就是将索要执行的任务,通过onHandleIntent回调到IntentService的实现类,让我们去进行具体的操作.
stopSelf()方法就是让我们在执行完耗时操作后,自动去Destroy该IntentService.

优点

所以我们还是要在总结一下IntentService的优点

  • 可执行耗时操作
  • 可以多次依次执行耗时操作
  • 执行完耗时操作后,会自动销毁.

8.0适配

  • 如果针对 Android 8.0 的应用不允许后台运行的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException。
  • 所以需要Context.startForegroundService() 函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。

广播

动静态广播对比

动态注册

动态就是通过代码的方式去注册广播.

  • context.registerReceiver()就是注册
  • unregisterReceiver()就是解绑.

至于广播的基本使用这里不做讲解.

优缺点

1.在代码中注册,灵活多变…
2.非常驻,可以跟随组件的生命周期变化.
3.组件生命周期结束前,需要进行注销.
4.应用场景,需要在特定的场合去进行监听广播.

不过在使用过程中需要注意的是:当内存不够的时候,资源会被回收,从生面周期的角度来说走到onPause之后就不会再走会被销毁,所以在广播就可能未被注销就会出现内存泄漏.所以最好在onResume的时候去注册广播,在onPause的时候去注销广播.

静态广播

静态广播:其实就是通过AndroidManifest文件,去注册广播.

优缺点

1.需要在AndroidManifest文件中声明.
2.常驻型的,不受任何声明周期的影响,app关闭之后任有消息.
3.耗电占内存
4.应用场景,需要时刻监听广播

广播类型

广播类型分为三种:普通广播,系统广播,有序广播

  • 普通广播:就是常规的自定义的广播
  • 系统广播:系统发出的广播,常利用系统的广播去监听开关机,锁屏,网络变化等.
  • 有序广播:通过AndroidManifest或者代码设置priority属性来表示优先级.

这里主要提一下有序广播:
1.priority越大则表示优先级越高.
2.优先级越高的,越早接收到数据
3.发送时需要用sendOrderedBroadcast发送广播.
4.可以在onReceive方法中,调用abortBroadcast()方法去拦截广播的传递.

android 8.0适配

在对比动静态广播的时候,我们提到静态广播是常驻型的,这就导致了非常的耗电,google也意识到了这一点,那么在8.0的时候为了优化耗电量就做了广播的限制.

原话就是8.0及以上系统对隐式广播做了限制.这就引出了隐式广播,何为隐式广播?
隐式广播:指那些没有指定接受App的广播.毫无疑问系统广播就是隐式广播,因为所有app都可以接收到.

长话短说,咱们来说说如何适配.

  • 动态广播不受限制,所以我们可以使用动态广播
  • 静态注册广播的时候,添加setPackage(制定包名字),就变成了显示广播
  • 针对系统广播,可以使用JobScheduler去监听一些广播.(JobScheduler后续会详讲)

下集预告

详细讲解跨进程通讯的Binder机制的过程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值