【Android】Service介绍和生命周期

news2024/9/20 13:40:00

人不走空

                                                                      

      🌈个人主页:人不走空      

💖系列专栏:算法专题

⏰诗词歌赋:斯是陋室,惟吾德馨

图片

 

介绍

Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件。Service是Android中实现程序后台运行的解决方案,它非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。

Android中的服务Service,和Activity不同的是不能与用户交互的,不能自己启动,系统的后台运行,当程序退出时,我们没有显示的调用停止服务,那么这个Service就没有结束,它仍然在后台运行。Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的操作。

服务一般分为两种:

  • 本地服务:用于应用程序内部,在Service可以调用startService()启动,调用stopService()结束,无论调用了多少次startService(),都只需调用一次stopService()来停止,采用startService()方法启动服务,只能调用stopService()方法结束服务,服务结束时会调用onDestroy()方法,。

  • 远程服务,用于系统内部的应用程序之间,可以定义接口并把接口暴露出来,以便其他应用进行操作,客户端建立到服务对象的连接,并通过那个连接来调用服务,调用bindService()方法建立连接,并启动,以调用unbindService()关闭连接,多个客户端可以绑定至同一个服务。

Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。

service在清单文件中的声明

不管是哪一种的 service ,也都需要在 AndroidManifest.xml中声明

<service android:name=".myservice"
            android:enabled="true"
            android:exported="true"
            android:icon="@drawable/background_blue"
            android:label="string"
            android:process="string"
            android:permission="string">
 </service>

说明:

字段说明
android:exported表示是否允许除了当前程序之外的其他程序访问这个服务
android:enabled表示是否启用这个服务
android:permission是权限声明
android:process是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
android:isolatedProcess设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。

生命周期

Service 的的生命周期会根据调用不同的方法启动有不同的表现,具体有两种形式。 

  • 通过 startService(Intent intent) 启动 Service 生命周期是这样的:onCreate() 、onStartCommand()、onStart()(已经过时) 、onDestroy() 

  • 通过 bindService(Intent intent,ServiceConnection conn,int flags) 启动 Service 生命周期是这样的:bindService()、onCreate() 、IBinder onBind(Intent intent)、unBindService()、onDestroy() 方法。 

图片

说明:

1.startService / stopService 

生命周期顺序:onCreate->onStartCommand->onDestroy

OnCreate() 

系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果service已经运行,这个方法不会被调用。 

onStartCommand() 

每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务。 

OnDestory() 

系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。 

2.bindService / unbindService 

生命周期顺序:onCreate->onBind->onUnBind->onDestroy 同样首先是OnCreate(),接着是 

OnBind() 当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。 

OnUnbind() 当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。 

最后是OnDestory() 

注意:通过bindService启动的Service的生命周期依附于启动它的Context。

start开启服务的生命周期:

  • 完整生命周期:onCreate()-->onStartCommand()-->onDestroy() 

  • 开启服务:onCreate()-->onStartCommand() 

  • 停止服务:onDestroy()

start开启服务的生命周期特点: 

1. 服务可以被开启多次,每次开启都调用onStartCommand 

2. 服务只能被停止一 

3. 长期运行在后台

bind绑定服务的生命周期

  • bindService(service, conn, flags); 

    service :意图 

    conn :activity和服务的连接通道 

    flags : BIND_AUTO_CREATE 连接的时候如果有服务的对象则复用,如果服务对象不存在,则创建一个服务的对象 

  • 完整生命周期:onCreate()-->onBind()-->onUnbind()-->onDestroy() 

  • 绑定服务:onCreate()-->onBind() 

  • 解绑服务:onUnbind()-->onDestroy()

bind绑定服务的生命周期特点: 

1. 服务只能被绑定一次,多次绑定无效 

2. 服务只能被解绑一次,多次解绑会抛出异常 

3. activity和绑定的Service是同生共死 

4. 绑定服务调用服务里的方法 

区别 

  • start开启服务可以长期运行在后台,服务组件在自己的应用程序中 

  • bind绑定服务可以调用服务里的方法,服务组件不在自己的应用程序中

IntentService与Service

Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。 

那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去你执行你的耗时操作。 

Service的官方介绍 

1.Service不是一个单独的进程 ,它和应用程序在同一个进程中。 

2.Service不是一个线程,所以我们应该避免在Service里面进行耗时的操作 IntentService:异步处理服务,新开一个线程:handlerThread在线程中发消息,然后接受处理完成后,会清理线程,并且关掉服务。 

IntentService有以下特点: 

1.它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。 

2.创建了一个工作队列,来逐个发送intent给onHandleIntent()。 

3.不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。 

4.默认实现的onBind()返回null 

5. 默认实现的onStartCommand()的目的是将intent插入到工作队列中 

继承IntentService的类至少要实现两个函数:构造函数和onHandleIntent()函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数

示例:

package com.loaderman.intentservicedemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService(new Intent(this,MyService.class));//主界面阻塞,最终会出现Application not responding
        //连续两次启动IntentService,会发现应用程序不会阻塞,而且最重要的是第二次的请求会再第一个请求结束之后运行(这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)
        startService(new Intent(this,MyIntentService.class));
        startService(new Intent(this,MyIntentService.class));
    }
}

package com.loaderman.intentservicedemo;
 
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

 
public class MyService extends Service {
 
    @Override
    public void onCreate() {
        super.onCreate();
    }
 
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        //经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作
        System.out.println("onStart");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("睡眠结束");
    }
 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

package com.loaderman.intentservicedemo;
 
import android.app.IntentService;
import android.content.Intent;
 
 
public class MyIntentService extends IntentService {
 
    public MyIntentService() {
        super("loaderman");
    }
 
    @Override
    protected void onHandleIntent(Intent intent) {
        // 经测试,IntentService里面是可以进行耗时的操作的
        //IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent
        //对于异步的startService请求,IntentService会处理完成一个之后再处理第二个
        System.out.println("onStart");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("睡眠结束");
    }
}

能否保证service不被杀死?

Service设置成START_STICKY kill 

后会被重启(等待5秒左右),重传Intent,保持与重启前一样 

提升service优先级

在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。 

【结论】目前看来,priority这个属性貌似只适用于broadcast,对于Service来说可能无效 

提升service进程优先级 

Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收 

当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以在startForeground()使用startForeground()将service放到前台状态。这样在低内存时被kill的几率会低一些。 

【结论】如果在极度极度低内存的压力下,该service还是会被kill掉,并且不一定会restart() 

onDestroy方法里重启service 

service +broadcast 方式,就是当service走onDestory()的时候,发送一个自定义的广播,当收到广播的时候,重新启动service 

也可以直接在onDestroy()里startService 

【结论】当使用类似口口管家等第三方应用或是在setting里-应用-强制停止时,APP进程可能就直接被干掉了,onDestroy方法都进不来,所以还是无法保证 

监听系统广播判断Service状态 

通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,别忘记加权限 

【结论】这也能算是一种措施,不过感觉监听多了会导致Service很混乱,带来诸多不便 

在JNI层,用C代码fork一个进程出来 

这样产生的进程,会被系统认为是两个不同的进程.但是Android5.0之后可能不行 

root之后放到system/app变成系统级应用 

大招: 放一个像素在前台(手机QQ)


作者其他作品:

【Java】Spring循环依赖:原因与解决方法

OpenAI Sora来了,视频生成领域的GPT-4时代来了

[Java·算法·简单] LeetCode 14. 最长公共前缀 详细解读

【Java】深入理解Java中的static关键字

[Java·算法·简单] LeetCode 28. 找出字a符串中第一个匹配项的下标 详细解读

了解 Java 中的 AtomicInteger 类

算法题 — 整数转二进制,查找其中1的数量

深入理解MySQL事务特性:保证数据完整性与一致性

Java企业应用软件系统架构演变史 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

强化学习的数学原理(1)

基本概念 State:在下面的例子中就是指每个位置&#xff08;location&#xff09;&#xff0c;例如s1、s2、s3…就是一个State&#xff0c;所有State的集合就是State Space(集合空间 S { s1,s2,s3,s4,s5…,s9 }) Action:每个状态可采取的行动&#xff0c;就如下面图片的例子&a…

openEuler 安装 podman 和 podman compose

在 openEuler 22.03 LTS SP4 中&#xff0c;你可以使用 dnf 包管理器来安装 Podman 和 Podman Compose。openEuler 默认使用 dnf 作为包管理器&#xff0c;所以这是安装软件的首选方式。 关于 openEuler 22.03 LTS SP4 下载地址&#xff1a; https://www.openeuler.org/zh/dow…

昇思MindSpore 25天学习打卡营|day20

GAN图像生成 模型简介 生成式对抗网络(Generative Adversarial Networks&#xff0c;GAN)是一种生成式机器学习模型&#xff0c;是近年来复杂分布上无监督学习最具前景的方法之一。 最初&#xff0c;GAN由Ian J. Goodfellow于2014年发明&#xff0c;并在论文Generative Adve…

Java中HashMap详解:hash原理、扩容机制、线程不安全及源码分析

前言 HashMap 是 Java 中常用的数据结构之一&#xff0c;用于存储键值对。在 HashMap 中&#xff0c;每个键都映射到一个唯一的值&#xff0c;可以通过键来快速访问对应的值&#xff0c;算法时间复杂度可以达到 O(1)。 HashMap 的实现原理是基于哈希表的&#xff0c;它的底层是…

Java语言程序设计——篇四(1)

类和对象 面向对象概述面向过程与面向对象面向对象基本概念面向对象的基本特征面向对象的优势及应用 为对象定义类类的修饰符成员变量成员变量-修饰符 构造方法⭐️成员方法成员方法-修饰符例题讲解 ⚠️理解栈和堆 面向对象概述 两种程序设计方法 结构化程序设计&#xff0c…

方波的傅里叶变换及方波的MATLAB实现

一、傅里叶变换简介 傅里叶变换&#xff0c;表示能将满足一定条件的某个函数表示成三角函数&#xff08;正弦和/或余弦函数&#xff09;或者它们的积分的线性组合。傅里叶变换是一种线性的积分变换。它的理论依据是&#xff1a;任何连续周期信号都可以由一组适当的正弦曲线组合…

Mac安装stable diffusion 工具

文章目录 1.安装 Homebrew2.安装 stable diffusion webui 的依赖3.下载 stable diffusion webui 代码4.启动 stable diffusion webui 本体5.下载模型6.这里可能会遇到一个clip-vit-large-patch14报错 参考&#xff1a;https://brew.idayer.com/install/stable-diffusion-webui/…

Unity 优化合集

1️⃣ 贴图优化 1. Read/Write Enable 这个属性勾选后允许你在运行时读取和写入纹理数据&#xff0c;这对于需要实时生成内容或者需要动态修改纹理的场合非常有用但在大部分情况下这是不必要的。如果打开这个属性&#xff0c;会使运行时贴图大小翻倍&#xff0c;内存中会额外…

浅谈C嘎嘎入门基础

看到这篇文章的童鞋或许会有疑惑&#xff0c;这不是之前 已经出过了吗&#xff0c;是的但是之前那篇文章可能不太好理解&#xff0c;因此我再写一篇便于大家理解的文章 那么上一篇文章已经帮大家过渡到C嘎嘎了&#xff0c;那么这篇文章我们继续讲解C嘎嘎的知识点。 C嘎嘎中的引…

牛客:DP25 删除相邻数字的最大分数(动态规划)

文章目录 1. 题目描述2. 解题思路3. 代码实现 1. 题目描述 2. 解题思路 题目的意思是选择某一个数&#xff0c;就会得到这个数 * 它出现的次数的分数&#xff0c;因此为了能快速统计出选择某一个数所能得到的分数&#xff0c;我们可以在输入数据时&#xff0c;使用一个数据来计…

C++的入门基础(二)

目录 引用的概念和定义引用的特性引用的使用const引用指针和引用的关系引用的实际作用inlinenullptr 引用的概念和定义 在语法上引用是给一个变量取别名&#xff0c;和这个变量共用同一块空间&#xff0c;并不会给引用开一块空间。 取别名就是一块空间有多个名字 类型& …

vue3+ECharts实现可视化中国地图

目录 版本问题解决 中国地图实现 版本问题解决 目前echarts的最新版本为5.5.1 echarts在4.9.0版本以后移除了中国地图&#xff0c;所以如果的你的版本高于4.9.0就需要手动导入中国地图。版本低于或者等于4.9.0则不需要导入。 这里我分享一种导入方法&#xff1a; 1.将项目的…

前端JS特效第34波:jQuery支持拖拽图片上传的图片批量上传插件

jQuery支持拖拽图片上传的图片批量上传插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>jQuery支持拖拽图片上传的图片批…

J027_递归算法

一、求n的阶乘 n的阶乘&#xff1a;1*2*3*4*...*n package com.itheima.d01_file;public class DiguiTest1 {public static void main(String[] args) {//求n的阶乘System.out.println(f(3));System.out.println(f(4));System.out.println(f(5));}private static int f(int n…

[激光原理与应用-111]:南京科耐激光-激光焊接-焊中检测-智能制程监测系统IPM介绍 - 15 - 常见缺陷与波形特征

目录 前言&#xff1a;激光焊接时的光谱特征 可见光 反射光 红外热辐射光 总结 一、动力电池 - 模组 - BusBar焊接 1.1 概述 1.2 没有缺陷波形&#xff1a;一条焊缝 1.3 保护气缺失 1. 可见光 2. 反射光 3. 红外光 综合分析 1.4 功率衰减 1. 可见光 2. 反射光 …

捷配生产总结-PCB上器件布局不好对SMTDIP的影响

在电子制造领域&#xff0c;PCB&#xff08;印刷电路板&#xff09;的设计至关重要&#xff0c;其中器件的布局更是影响着整个生产流程的效率和质量。特别是对于 SMT&#xff08;表面贴装技术&#xff09;和 DIP&#xff08;双列直插式封装&#xff09;这两种常见的组装工艺&am…

STM32之七:SPI通信

目录 1.SPI通信简介 1.1 主从模式 1.2 4根通信线 1.3 数据传输 2. SPI总线时序及其4种工作模式 2.1 SPI数据移位示意 2.2 SPI四种工作模式 2.2.1 mode 0 &#xff1a;CPOL 0,CPHA0 2.2.2 mode 1&#xff1a; CPOL 0&#xff0c;CPHA 1 2.2.3 mode 2&#xff1a; C…

2024-07-14 Unity插件 Odin Inspector1 —— 插件介绍

文章目录 1 介绍2 模块3 学习目的 1 介绍 ​ Odin Inspector 是 Unity 的一个插件&#xff0c;拥有强大、自定义和用户友好的编辑器&#xff0c;而无需编写任何自定义编辑器代码&#xff0c;使得编程过程中的数据可视化更容易实现。 ​ 具体功能包括&#xff1a; 更舒适美观…

新一代大语言模型 GPT-5 对工作与生活的影响及应对策略

文章目录 &#x1f4d2;一、引言 &#x1f4d2;二、GPT-5 的发展背景 &#x1f680;&#xff08;一&#xff09;GPT-4 的表现与特点 &#x1f680;&#xff08;二&#xff09;GPT-5 的预期进步 &#x1f4d2;三、GPT-5 对工作的影响 &#x1f680;&#xff08;一&#xf…

FreeRTOS学习(1)STM32单片机移植FreeRTOS

一、FreeRTOS源码的下载 1、官网下载 FreeRTOS官方链接 官方下载速度慢&#xff0c;需要翻墙&#xff0c;一般选择第一个 2、直接通过仓库下载 仓库地址链接 同样很慢&#xff0c;甚至打不开网页&#xff0c;也不建议使用这种方法。 3、百度网盘 链接&#xff1a;https:…