Android Service最全面的解析

2023-11-08

本篇文章再次来自 刘明渊 ,话说刘明渊已经是我公众号的老熟人了,这是第三次发表他投稿的文章。前两篇关于Intent的译文都广受大家好评,而本篇对于Service的译文同样精彩。其实像这种官方文档翻译类文章的投稿我都是非常欢迎的,因为官方文档的质量首先是有保障的,再者解决了一些无法直接看英文文档或者翻不了墙的朋友的阅读障碍,希望有更多的朋友可以来多多投稿。


刘明渊 的博客地址:http://blog.csdn.net/vanpersie_9987


Service


Service是Android中一个类,它是Android四大组件之一,使用Service可以在后台执行长时间的操作( perform long-running operations in the background ),Service并不与用户产生UI交互。其他的应用组件可以启动Service,即便用户切换了其他应用,启动的Service仍可在后台运行。一个组件可以与Service绑定并与之交互,甚至是跨进程通信(IPC)。例如,一个Service可以在后台执行网络请求、播放音乐、执行文件读写操作或者与 content provider交互等。


本文将介绍Services的定义、创建、启动、绑定、前台Service等相关内容。


Service有两种启动形式:


  • Started:其他组件调用startService()方法启动一个Service。一旦启动,Service将一直运行在后台(run in the background indefinitely)即便启动Service的组件已被destroy。通常,一个被start的Service会在后台执行单独的操作,也并不给启动它的组件返回结果。比如说,一个start的Service执行在后台下载或上传一个文件的操作,完成之后,Service应自己停止。


  • Bound:其他组件调用bindService()方法绑定一个Service。通过绑定方式启动的Service是一个client-server结构,该Service可以与绑定它的组件进行交互。一个bound service仅在有组件与其绑定时才会运行(A bound service runs only as long as another application component is bound to it),多个组件可与一个service绑定,service不再与任何组件绑定时,该service会被destroy。


当然,service也可以同时在上述两种方式下运行。这涉及到Service中两个回调方法的执行:onStartCommand()(通过start方式启动一个service时回调的方法)、onBind()(通过bind方式启动一个service回调的方法)。


无论通过哪种方式启动service(start、bind、start&bind),任何组件(甚至其他应用的组件)都可以使用service。并通过Intent传递参数。当然,您也可以将Service在manifest文件中配置成私有的,不允许其他应用访问。


请注意:Service运行在主线程中(A service runs in the main thread of its hosting process),Service并不是一个新的线程,也不是新的进程。也就是说,若您需要在Service中执行较为耗时的操作(如播放音乐、执行网络请求等),需要在Service中创建一个新的线程。这可以防止ANR的发生,同时主线程可以执行正常的UI操作。


使用Service还是使用Thread?


Service是一个运行在后台的组件,并不与用户交互。您仅在需要的时候创建Service( create a service only if that is what you need)。


当用户正在与UI交互时,需要执行一些主线程无法完成的工作,应当创建一个线程。例如当activity正在运行时,需要播放音乐,此时需要在Activity的onCreate()中创建线程并在onStart()中开启。最后在onStop()中停止。您也可以考虑使用AsyncTask 或 HandlerThread来替代Thread创建线程。



Service基础


为了创建Service,需要继承Service类。并重写它的回调方法,这些回调方法反应了Service的生命周期,并提供了绑定Service的机制。最重要的Service的生命周期回调方法如下所示:


  • onStartCommand()当其他组件调用startService()方法请求启动Service时,该方法被回调。一旦Service启动,它会在后台独立运行。当Service执行完以后,需调用stopSelf() 或 stopService()方法停止Service。(若您只希望bind Service,则无需调用这些方法)


  • onBind()当其他组件调用bindService()方法请求绑定Service时,该方法被回调。该方法返回一个IBinder接口,该接口是Service与绑定的组件进行交互的桥梁。若Service未绑定其他组件,该方法应返回null。


  • onCreate():当Service第一次创建时,回调该方法。该方法只被回调一次,并在onStartCommand() 或 onBind()方法被回调之前执行。若Service处于运行状态,该方法不会回调。


  • onDestroy()当Service被销毁时回调,在该方法中应清除一些占用的资源,如停止线程、接触绑定注册的监听器或broadcast receiver 等。该方法是Service中的最后一个回调。


如果某个组件通过调用startService()启动了Service(系统会回调onStartCommand()方法),那么直到在Service中手动调用stopSelf()方法、或在其他组件中手动调用stopService()方法,该Service才会停止。


如果某个组件通过调用bindService()绑定了Service(系统不会回调onStartCommand()方法),只要该组件与Service处于绑定状态,Service就会一直运行,当Service不再与组件绑定时,该Service将被destroy。


当系统内存低时,系统将强制停止Service的运行;若Service绑定了正在与用户交互的activity,那么该Service将不大可能被系统kill( less likely to be killed)。如果创建的是前台Service,那么该Service几乎不会被kill(almost never be killed)。否则,当创建了一个长时间在后台运行的Service后,系统会降低该Service在后台任务栈中的级别——这意味着它容易被kill(lower its position in the list of background tasks over time and the service will become highly susceptible to killing),所以在开发Service时,需要使Service变得容易被restart,因为一旦Service被kill,再restart它需要其资源可用时才行(restarts it as soon as resources become available again ),当然这也取决于onStartCommand()方法返回的值,这将在后续介绍。


在manifest文件中注册 Service


在manifest文件中注册service的方式如下:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</
manifest>

除此之外,在<service>标签中还可以配置其他属性,比如,需要启动该service所需的权限、该service应运行在哪个进程中 等( permissions required to start the service and the process in which the service should run)。android:name属性是唯一不可缺省的,它指定了Service的全限定类名。一旦发布了应用,该类名将不可更改。


请注意:为了保证应用的安全,请使用显式Intent启动或绑定一个Service,请不要在<service>标签中配置intent-filter。


若不确定该启动哪个Service,那么可以在<service>中配置intent-filter,并在Intent中排除该Service(supply intent filters for your services and exclude the component name from the Intent),但必须调用Intent的setPackage()方法,来为启动的service消除歧义(provides sufficient disambiguation for the target service)。


注:setPackage()方法传入一个String参数,代表一个包名。该方法表示该Intent对象只能在传入的这个包名下寻找符合条件的组件,若传入null,则表示可以在任意包下寻找。


android:exported属性设为false,表示不允许其他应用程序启动本应用的组件,即便是显式Intent也不行(even when using an explicit intent)。这可以防止其他应用程序启动您的service组件。


继承 IntentService


在大多数情况下,start Service并不会同时处理多个请求(don't need to handle multiple requests simultaneously),因为处理多线程较为危险(a dangerous multi-threading scenario),所以继承IntentService类带创建Service是个不错选择。


使用IntentService的要点如下:


  • 默认在子线程中处理回传到onStartCommand()方法中的Intent;


  • 在重写的onHandleIntent()方法中处理按时间排序的Intent队列,所以不用担心多线程(multi-threading)带来的问题。


  • 当所有请求处理完成后,自动停止service,无需手动调用`stopSelf()`方法;


  • 默认实现了onBind()方法,并返回null;


  • 默认实现了onStartCommand()方法,并将回传的Intent以序列的形式发送给onHandleIntent(),您只需重写该方法并处理Intent即可。


综上所述,您只需重写onHandleIntent()方法即可,当然,还需要创建一个构造方法,示例如下:



如果您还希望在IntentService 的继承类中重写其他生命周期方法,如onCreate()、onStartCommand() 或 onDestroy(),那么请先调用各自的父类方法以保证子线程能够正常启动。


比如,要实现onStartCommand()方法,需返回其父类方法:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
   Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
   return super.onStartCommand(intent,flags,startId); }

onHandleIntent()外,onBind()方法也无需调用其父类方法。


继承 Service


如果您需要在Service中执行多线程而不是处理一个请求队列(perform multi-threading instead of processing start requests through a work queue),那么需要继承Service类,分别处理每个Intent。


在Service中执行操作时,处理每个请求都需要开启一个线程,并且同一时刻一个线程只能处理一个请求( for each start request, it uses a worker thread to perform the job and processes only one request at a time)。




注意到onStartCommand()返回一个整形变量,该变量必须是下列常量之一:


  • START_NOT_STICKY:若执行完onStartCommand()方法后,系统就kill了service,不要再重新创建service,除非系统回传了一个pending intent。这避免了在不必要的时候运行service,您的应用也可以restart任何未完成的操作。


  • START_STICKY:若系统在onStartCommand()执行并返回后kill了service,那么service会被recreate并回调onStartCommand()。dangerous不要重新传递最后一个Intent(do not redeliver the last intent)。相反,系统回调onStartCommand()时回传一个空的Intent,除非有 pending intents传递,否则Intent将为null。该模式适合做一些类似播放音乐的操作。


  • START_REDELIVER_INTENT:若系统在onStartCommand()执行并返回后kill了service,那么service会被recreate并回调onStartCommand()并将最后一个Intent回传至该方法。任何 pending intents都会被轮流传递。该模式适合做一些类似下载文件的操作。


启动 Service


若需要启动Service,见下面所示:

Intent intent = new Intent(this, HelloService.class);
startService(intent);

startService(intent)方法将立即返回,并回调onStartCommand()(请不要手动调用该方法),若该Service未处于运行状态,系统将首先回调onCreate(),接着再回调onStartCommand()。若您希望Service可以返回结果,那么需要通过调用getBroadcast返回的PendingIntent启动Service(将PendingIntent包装为Intent),service可使用broadcast 传递结果。


多个启动Service的请求可能导致onStartCommand()多次调用,但只需调用stopSelf() 、 stopService()这两个方法之一,就可停止该服务。


停止 Service


一个启动的Service必须管理自己的生命周期。系统不会主动stop或destroy一个运行的Service,除非系统内存紧张,否则,执行完onStartCommand()方法后,Service依然运行。停止Service必须手动调用stopSelf()(在Service中)或调用stopService()(在启动组件中)。


一旦调用了上述两种方法之一,系统会尽快destroy该Service(as soon as possible)。


若系统正在处理多个调用onStartCommand()请求,那么在启动一个请求时,您不应当在此时停止该Service(you shouldn’t stop the service when you’re done processing a start request)。为了避免这个问题,您可以调用stopSelf(int)方法,以确保请求停止的Service时最新的启动请求( your request to stop the service is always based on the most recent start request)。这就是说,当调用stopSelf(int)方法时,传入的ID代表启动请求(该ID会传递至onStartCommand()),该ID与请求停止的ID一致。则如果在调用stopSelf(int)之前,Service收到一个新的Start请求,ID将无法匹配,Service并不会停止。


为了节省内存和电量,当Service完成其工作后将其stop很有必要。如有必要,可以在其他组件中调用stopService()方法,即便Service处于绑定状态,只要它回调过onStartCommand(),也应当主动停止该Service。


绑定 Service


通过其他组件调用bindService()方法可以绑定一个Service以保持长连接,这时一般不允许其他组件调用startService()启动Service。


当其他组件需要与Service交互或者需要跨进程通信时,可以创建一个bound Service。


为创建一个bound Service,必须重写`onBind()`回调,该方法返回一个IBinder接口。该接口时组件与Service通信的桥梁。组件调用bindService()与Service绑定,该组件可获取IBinder接口,一旦获取该接口,就可以调用Service中的方法。一旦没有组件与Service绑定,系统将destroy它,您不必手动停止它。


为创建一个bound Service,必须定义一个接口 ,该接口指定组件与Service如何通信。定义的接口在组件与Service之间,且必须实现IBinder接口。这正是onBind()的返回值。一旦组件接收了IBinder,组件与Service便可以开始通信。


多个组件可同时与Service绑定,当组件与Service交互结束后,可调用unbindService()方法解绑。bound Service比start Service要复杂,故我将在后续单独翻译。


向用户发送通知


运行中的Service可以通过Toast Notifications 或 Status Bar Notifications 向用户发送通知。Toast是一个可以短时间弹出的提醒框。Status Bar是顶部状态栏中出现的太有图标的信息,用户可以通过下拉状态栏获得具体信息并执行某些操作(如启动Activity)。


通常,Status Bar用于通知某些操作已经完成,如下载文件完成。当用户下拉状态栏后,点击该通知,可获取详细内容,如查看该下载的文件。


在前台运行 Service


前台Service用于动态通知消息,如天气预报。该Service不易被kill。前台Service必须提供status bar,只有前台Service被destroy后,status bar才能消失。


举例来说,一个播放音乐的Service必须是前台Service,只有这样用户才能确知其运行状态。为前台Service提供的status bar可以显示当前音乐的播放状态,并可以启动播放音乐的Activity。


调用startForeground()可以启动前台Service。该方法接收两个参数,参数一是一个int型变量,用户指定该通知的唯一性标识,而参数而是一个Notification用于配置status bar,示例如下:




调用stopForeground()来移除(remove)前台Service。该方法需传入一个boolean型变量,表示是否也一并清除status bar上的notification(indicating whether to remove the status bar notification as well)。该方法并不停止Service,如果停止正在前台运行的Service,那么notification 也一并被清除。


Service 的生命周期


从Service的启动到销毁,有两种路径:

  • A started service:需手动停止 

  • A bound service:可自动停止


如下图所示 :


这两条路径并不是毫不相干的:当调用startService()启动一个Service后,您仍可以bind该Service。比如,当播放音乐时,需调用startService()启动指定播放的音乐,当需要获取该音乐的播放进度时,有需要调用bindService(),在这种情况下,知道Service被unbind ,调用stopService() 或stopSelf()都不能停止该Service。


Service 的生命周期回调



这些生命周期方法在使用时无需调用各自的父类方法。


在两条生命周期路径中,都包含了两个嵌套的生命周期:

  • 完整生命周期( entire lifetime ):从onCreate()被调用到onDestroy()返回。与Activity类似,一般在onCreate()中做一些初始化工作,而在onDestroy()做一些资源释放工作。如,若Service在后台播放一个音乐,就需要在onCreate()方法中开启一个线程启动音乐,并在onDestroy()中结束线程。


无论是startService() 还是 bindService()启动Service,onCreate() 和 onDestroy()均会被回调。


  • 活动生命周期(active lifetime):从onStartCommand() 或 onBind()回调开始。由相应的startService() 或 bindService()调用。若是Start Service,那么Service的活动生命周期结束就意味着其完整生命周期结束 (the active lifetime ends the same time that the entire lifetime ends),即便onStartCommand()返回后,Service仍处于活动状态;若是bound Service,那么当onUnbind()返回时,Service的活动生命周期结束。


请注意:针对startService(),由于Service中没有类似onStop()的回调,所以在调用stopSelf() 或 stopService()后,只有onDestroy()被回调标志着Service已停止。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Service最全面的解析 的相关文章

  • Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from

    程序在编译时报错 在执行合并AndroidMainfest时报Attribute application appComponentFactory value android support v4 app CoreComponentFacto
  • 【Android】线性布局(LinearLayout)最全解析

    Android 线性布局 LinearLayout 最全解析 一 LinearLayout概述 二 LinearLayout常用属性 2 1 orientation属性 2 2 gravity属性 2 3 layout weight属性 一
  • kotlin实现java的单例模式

    代码 package com flannery interviewdemo singleinstance https blog csdn net Jason Lee155 article details 128796742 Java实现 p
  • Android 对data/data/(your packagename)目录下的数据读写、删除操作

    一 数据存储 App自身的数据存储在 data data packagename 目录下 大致结构如下图 Activity提供了getCacheDir 和getFilesDir 方法 getCacheDir getAbsolutePath
  • Kotlin1.8新特性

    Kotlin1 8 0新特性 新特性概述 JVM 的新实验性功能 递归复制或删除目录内容 提升了 kotlin reflect 性能 新的 Xdebug 编译器选项 提供更出色的调试体验 kotlin stdlib jdk7 与 kotli
  • Android file类使用详解

    一 Android file类 在开发Android应用时免不了会跟文件打交道 本篇文章记录总结自己常用到的文件操作 数据的存储有多种方式 比如数据库存储 SharedPreferences存储 文件存储等 这里我们将要介绍最简单的文件存储
  • Android内存泄露

    Android内存泄露概述 了解Android内存泄露之前 需要对java的内存管理和GC机制有个简单的了解 Android内存泄露的根本原因是引用者的生命周期大于被引用者 举个例子 有对象A B B有A的强引用 GC要回收A时发现B还未销
  • 【Android】WebView控件最全使用解析

    WebView控件最全使用解析 一 WebView 概述 二 WebView使用基础篇 2 1添加方式 2 2 加载远程网页 2 3 加载本地网页 2 4 加载HTML片段 2 5 WebView 常用方法 三 WebView 进阶篇 3
  • Android开发基础 -- android studio 使用第三方模拟器连接方法,如海马玩模拟器

    安装完模拟器后 要使用adb命令Android studio才能识别出来 打开cmd 输入 adb connect 127 0 0 1 26944 如下 海马玩模拟器的端口号是26944 逍遥安卓模拟器的端口号是21503 夜神玩模拟器的端
  • 源码环境下添加系统Service流程

    关于系统服务的分析 以及如何实现添加系统服务 分析详细跳转链接 Android系统服务 SystemService 简介 添加系统Service涉及的文件 修改文件 Android mk api current txt api system
  • 拉伸无锯齿的SVG图片

    package com moonlight example import com larvalabs svgandroid SVG import android content Context import android graphics
  • Android Studio连接夜神模拟器

    Android Studio连接夜神模拟器 一 下载夜神模拟器 二 夜神模拟器连接Android Studio 三 其他操作 3 1 屏幕旋转 3 2 创建其他模拟器 一 下载夜神模拟器 官网 https www yeshen com 下载
  • AndroidManifest.xml中android:configChanges的简介

    程序在运行时 一些设备的配置可能会改变 如 横竖屏的切换 键盘的可用性等 这样的事情一发生 Activity会重新启动 其中的过程是 在销毁之前会先 called onSaveInstanceState 去保存你应用中的一些数据 然后cal
  • Android 开发最佳实践

    https github com futurice android best practices blob master translations Chinese README cn md 组织好它们 在layoutout XMLs布局时
  • FloatingActionButton的使用

    FloatingActionButton FAB 是 Android 5 0 新特性 Material Design 中的一个控件 是一种悬浮的按钮 FloatingActionButton 是 ImageView 的子类 因此它具备Ima
  • 『Android Studio』用Fragment实现一个简易新闻浏览界面

    Fragment意思为碎片 片段 在Android中有些Activity在手机上看起来很美观 但放在屏幕更大的平板类的设备上 可能就不一样了 而Fragment能在一个Activity中内嵌多个独立的小Activity 有效的解决了app在
  • Android Service最全面的解析

    本篇文章再次来自 刘明渊 话说刘明渊已经是我公众号的老熟人了 这是第三次发表他投稿的文章 前两篇关于Intent的译文都广受大家好评 而本篇对于Service的译文同样精彩 其实像这种官方文档翻译类文章的投稿我都是非常欢迎的 因为官方文档的
  • C/C++在Android开发中的应用

    JNI开发系列阅读 JNI与底层调用1 http blog csdn net axi295309066 article details 60758515 JNI与底层调用2 http blog csdn net axi295309066 a
  • 关于TextView和ImageView的背景及透明设置小结

    关于TextView和ImageView的背景及透明设置小结 关于ImageView的相关设置 设置背景颜色 ImageView setBackgroundColor android graphics Color parseColor f3
  • Gradle入门(二)尝试理解gralde编译项目

    前言 前面我们了解了如何通过groovy DSL转换为KTS 我也在尝试的证明可以看到源码和有代码提示对于入门的重要性 2022年11月12日 我发现最新的idea 有gradle的代码提示 点击也可以看到源码 学习Gradle还是建议整一

随机推荐

  • LeetCode--初级算法--环形链表

    题目 给定一个链表 判断链表中是否有环 为了表示给定链表中的环 我们使用整数 pos 来表示链表尾连接到链表中的位置 索引从 0 开始 如果 pos 是 1 则在该链表中没有环 示例 1 输入 head 3 2 0 4 pos 1 输出 t
  • Excel条件格式化(conditional formatting)应用

    简介 条件格式化顾名思义就是根据条件对单元格进行格式化 填充 字体等 比如我们有一个学生成绩表 根据需要我们要把成绩按 不及格 lt 60 良好 gt 60且 lt 90 优秀 gt 90 进行颜色标注 第一步 如图 第二步 如图 点击 确
  • OpenMP task 原理与实例

    个人理解 Openmp自从3 0以后全面走向任务驱动 task机制非常重要 可以显式定义任务 而其余parallel代码块中不用task定义的实际上是隐式任务 抽象来说就是有两个池子 线程池与任务池 闲置的线程会在线程池等待任务 显式任务与
  • Servlet登录注册(IDEA)

    user类 提供get set 有参 无参 toString方法 UserDao层 UserDaoImpl层 登录 注册是否重复 真正的注册 UserService层 登录LoginServlet层 注册和注册用户唯一的ZcServlet层
  • html,css,js简单介绍,html常用标签

    目录 简单介绍 HTML常用标签 1 html骨架标签 2 标题标签 3 段落标签 4 换行标签 5 文本格式化标签 6 div标签 span标签和pre标签 7 图像标签 8 超链接标签 9 注释标签 10 表格标签 11 列表标签 12
  • Geometry Shader 概念和实例

    前言 Shader Model 4给我们带来了Geometry Shader这个玩意儿 其实这个东西早就在一些3D动画制作软件中存在了 比如Maya 8 我参考了以前DX10的哪一篇Preview与Csustan edu的一篇比较详尽的教材
  • C语言实现url解析小实例

    一 前言 前面一口君写了一篇关于url的文章 一文带你理解URI 和 URL 有什么区别 本篇在此基础上 编写一个简单的用于解析url的小例子 最终目标是解析出URL中所有的数据信息 二 库函数 用到的几个库函数如下 1 strncasec
  • Dota数据集介绍

    文章目录 前言 DOTA数据集介绍 DOTAV1 0 DOTAV1 5 DOTAV2 0 标注方式 Task1 Detection with oriented bounding boxes Task2 Detection with hori
  • 基于Android+OpenCV+CNN+Keras的智能手语数字实时翻译——深度学习算法应用(含Python、ipynb工程源码)+数据集(四)

    目录 前言 总体设计 系统整体结构图 系统流程图 运行环境 模块实现 1 数据预处理 2 数据增强 3 模型构建 4 模型训练及保存 5 模型评估 6 模型测试 1 权限注册 2 模型导入 3 总体模型构建 4 处理视频中的预览帧数据 5
  • erlang 实现二叉树

    此为一练习题 为 Erlang程序设计 第7章后的练习题 7 5 二叉树记录 建立二叉树 ifdef debug define DBG Str Args io format Str Args else define DBG Str Args
  • 20230626 数学

    1 极大似然估计 Maximum likelihood estimation 最大似然估计 大道上的头陀的博客 CSDN博客 极大似然估计的应用场景 极大似然估计 Maximum Likelihood Estimation MLE 是统计学
  • [leetcode 周赛 148] 1144 递减元素使数组呈锯齿状

    目录 1144 Decrease Elements To Make Array Zigzag 递减元素使数组呈锯齿状 描述 思路 代码实现 1144 Decrease Elements To Make Array Zigzag 递减元素使数
  • vue实现简单搜索功能

    目录 1 概述 2 功能逻辑 2 1功能流程 2 2 流程图 3 功能实现 3 1 vue组件化 3 2 代码 3 3 动态效果 1 概述 在vue项目中 搜索功能是我们经常需要使用的一个场景 最常用的是在列表数据中搜索一个想要的 今天的例
  • C语言stat()函数:获取文件状态

    C语言stat 函数 获取文件状态 相关函数 fstat lstat chmod chown readlink utime 头文件 include
  • 【Bcos】create BcosSDK failed, error info: init channel network error

    create BcosSDK failed error info init channel network error Try init the sslContext failed Try init the sslContext faile
  • 功能强大的国产Api管理工具

    前言 如果你是一名Java后端开发工程师 像Swagger Postman RAP这些工具 应该再熟悉不过了吧 为我们的接口开发工作带来了很多的便捷 不过因为这些都是独立的框架 之间并不存在互通性 因此在多个框架间协调的时候 不可避免的会带
  • Anaconda下Jupyter Notebook执行OpenCV中cv2.imshow()报错(错误码为1272)网上解法汇总记录和最终处理方式

    零 我设备的相关信息 Python 3 8 8 Anaconda3 2021 05 查询匹配python3 8 的OpenCV匹配版本为 4 1 4 2 我最后安装4 2 0 32版本 如下我记录了 从发现问题 到不断试错 最后解决问题 的
  • 电视制式 NTSC PAL SECAM

    电视制式 电视的制式是指电视信号的标准 目前各国的电视制式不尽相同 如附件1 2 制式的区分主要在于其帧频 场频 的不同 分解率的不同 信号带宽以及载频的不同 色彩空间的转换关系不同等 电视制式现在有模拟和数字信号和数字信号两种 模拟制式一
  • 【Linux】进程篇(补):守护进程

    文章目录 1 补充 1 1 查看 1 2 控制进程组的方式 2 创建守护进程 step1 忽略信号 step2 让自己不是组长 step3 setsid 函数 给调用函数设置新的会话和进程组 ID step4 chdir 函数 可以改变守护
  • Android Service最全面的解析

    本篇文章再次来自 刘明渊 话说刘明渊已经是我公众号的老熟人了 这是第三次发表他投稿的文章 前两篇关于Intent的译文都广受大家好评 而本篇对于Service的译文同样精彩 其实像这种官方文档翻译类文章的投稿我都是非常欢迎的 因为官方文档的