当前位置: 首页 > news >正文

Android 四大组件 service

前言

在Android系统中,Service 是一个用来执行长时间运行的操作而不提供用户界面的应用组件。它可以在后台执行任务,即使用户切换到其他应用也不会被中断。

Service 在Android中主要用于在后台执行长时间运行的任务,例如播放音乐、执行文件下载、处理网络请求等。尽管Service运行在后台,但它仍然属于应用程序的一部分,因此不会影响用户对前台应用的交互。

Service的类型

在Android中,Service 可以分为三种类型:

前台Service

前台Service 是用户可见的服务,它会在系统的通知区域显示一个通知,表示正在运行的服务。这种类型的Service被视为用户当前活跃的一部分,因此系统不太可能在内存不足时终止它。前台Service 常用于音乐播放或GPS导航等需要用户明确知道并持续运行的功能。

后台Service

后台Service 在用户不可见的情况下执行操作,通常用于执行不需要与用户交互的任务。但从Android Oreo(API 级别 26)开始,后台服务的使用受到了严格限制,以减少对系统性能的影响和提升电池寿命。

绑定Service

绑定Service 是一种允许应用组件(如Activity)绑定到Service并与之交互的服务。组件可以发送请求、接收响应,甚至进行进程间通信(IPC)。绑定的Service 只在其他应用组件与其绑定时运行,不会无限期运行。

Service的实现

实现Service 主要涉及以下几个步骤:

  • 定义Service: 在Java或Kotlin文件中扩展Service基类,并重写其生命周期方法如onCreate(), onStartCommand(), onBind(), 和onDestroy()

  • 配置Manifest: 在AndroidManifest.xml中声明Service,并设置适当的权限和属性。

  • 启动和绑定Service: 通过startService(Intent)方法启动服务,或者使用bindService(Intent, ServiceConnection, int)绑定服务。前者适用于执行单一操作或执行不返回结果的操作,后者适用于与服务进行交互。

如下是一个例子:创建一个服务,允许用户在后台播放音乐,即使他们离开了应用,音乐仍然可以继续播放:

public class MusicService extends Service {private MediaPlayer mediaPlayer;@Overridepublic void onCreate() {super.onCreate();// 初始化 MediaPlayer 对象mediaPlayer = MediaPlayer.create(this, R.raw.sample_music);mediaPlayer.setLooping(true); // 设置音乐循环播放}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {mediaPlayer.start(); // 开始播放音乐return START_STICKY; // 系统如果终止服务后,会尝试重新创建服务并调用 onStartCommand()}@Overridepublic void onDestroy() {super.onDestroy();if (mediaPlayer != null) {mediaPlayer.stop();mediaPlayer.release();}}@Overridepublic IBinder onBind(Intent intent) {return null; // 不提供绑定功能}
}
<service android:name=".MusicService" />
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button startButton = findViewById(R.id.startButton);Button stopButton = findViewById(R.id.stopButton);startButton.setOnClickListener(v -> startService(new Intent(this, MusicService.class)));stopButton.setOnClickListener(v -> stopService(new Intent(this, MusicService.class)));}
}

管理Service的生命周期

主要包括:

  • onCreate(): 当服务第一次创建时调用。
  • onStartCommand(): 每次通过 startService() 方法启动服务时调用。
  • onBind(): 当其他组件想要与服务绑定时调用。
  • onUnbind(): 当所有组件都与服务解绑时调用。
  • onDestroy(): 当服务不再使用且将被销毁时调用。

与服务通信

Binder

对于在同一应用内运行的服务,可以通过定义一个 Binder 类并在服务中返回这个 Binder 的实例,从而实现与服务的通信。客户端(如 Activity)可以绑定到服务并获得这个 Binder 对象,通过这个对象调用服务中的方法。

public class LocalService extends Service {// Binder 类的实例,用于返回给客户端private final IBinder binder = new LocalBinder();public class LocalBinder extends Binder {LocalService getService() {// 返回当前的 LocalService 实例以供客户端调用公开的方法return LocalService.this;}}@Overridepublic IBinder onBind(Intent intent) {return binder;}// 服务中的一个方法,客户端可以调用public int getRandomNumber() {return new Random().nextInt(100);}
}
public class MainActivity extends AppCompatActivity {private LocalService localService;private boolean isBound = false;private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {LocalBinder binder = (LocalBinder) service;localService = binder.getService();isBound = true;}@Overridepublic void onServiceDisconnected(ComponentName arg0) {isBound = false;}};@Overrideprotected void onStart() {super.onStart();bindService(new Intent(this, LocalService.class), connection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();if (isBound) {unbindService(connection);isBound = false;}}public void onButtonClick(View v) {if (isBound) {// 调用服务的方法int num = localService.getRandomNumber();Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();}}
}
Messager

如果服务需要与多个应用组件或其他应用进行跨进程通信,可以使用 Messenger。在这种方式a中,服务使用 Handler 接收消息,并通过 Messenger 对象响应。

public class MessengerService extends Service {static final int MSG_SAY_HELLO = 1;class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_SAY_HELLO:Toast.makeText(getApplicationContext(), "Hello!", Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);}}}final Messenger messenger = new Messenger(new IncomingHandler());@Overridepublic IBinder onBind(Intent intent) {return messenger.getBinder();}
}
public class ActivityMessenger extends AppCompatActivity {Messenger messenger = null;boolean isBound;private ServiceConnection connection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {messenger = new Messenger(service);isBound = true;}public void onServiceDisconnected(ComponentName className) {messenger = null;isBound = false;}};public void sayHello(View v) {if (!isBound) return;Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);try {messenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}
}
AIDL

AIDL(Android Interface Definition Language)是一种接口定义语言,用于让客户端和服务之间能够在不同的进程中进行通信。使用 AIDL 是处理复杂数据传输或跨应用通信的标准方式。

定义一个 AIDL 文件,这个文件描述了服务将要公开的接口

interface IRandomNumberService {int getRandomNumber();
}

当构建项目时,Android 构建工具会根据 AIDL 文件生成一个 Java 接口。然后可以创建一个实现这个接口的服务:

IRandomNumberService.Stub 是由 AIDL 文件自动生成的,需要实现这个 Stub 类中的方

public class RandomNumberService extends Service {private final IRandomNumberService.Stub binder = new IRandomNumberService.Stub() {public int getRandomNumber() throws RemoteException {return new java.util.Random().nextInt(100);}};@Overridepublic IBinder onBind(Intent intent) {return binder;}
}

现在,任何其他应用都可以绑定到这个服务并调用 getRandomNumber 方法

public class ClientActivity extends AppCompatActivity {private IRandomNumberService randomNumberService;private boolean isBound = false;private ServiceConnection connection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {randomNumberService = IRandomNumberService.Stub.asInterface(service);isBound = true;}public void onServiceDisconnected(ComponentName className) {randomNumberService = null;isBound = false;}};@Overrideprotected void onStart() {super.onStart();bindService(new Intent("com.example.myapp.RandomNumberService"),connection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();if (isBound) {unbindService(connection);isBound = false;}}public void onButtonClick() {if (isBound) {try {int randomNumber = randomNumberService.getRandomNumber();// Use the random number...} catch (RemoteException e) {e.printStackTrace();}}}
}

相关文章:

  • Firefox国际版
  • 【调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件】
  • Jeecg | 如何解决 ERR Client sent AUTH, but no password is set 问题
  • 前端应用开发实验:表单控件绑定
  • 什么叫USDT(泰达币)的前世今生!
  • JavaScript tab选项卡切换
  • 分享一个思路,使用插桩技术解决慢查询测试问题
  • 16:00面试,16:08就出来了,问的问题有点变态。。。
  • 【网络版本计算器的实现】
  • Scikit-Learn随机森林回归
  • Java设计模式:享元模式实现高效对象共享与内存优化(十一)
  • 音乐传奇告别之作:《杰作》未解之谜❗❗
  • YOLOv7添加注意力机制和各种改进模块
  • 微信聊天内容怎么监控? | 三款可以监控电脑微信聊天记录的软件大盘点
  • 每日两题 / 131. 分割回文串 42. 接雨水(LeetCode热题100)
  • Apache Zeppelin在Apache Trafodion上的可视化
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • JS字符串转数字方法总结
  • Making An Indicator With Pure CSS
  • mockjs让前端开发独立于后端
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • spark本地环境的搭建到运行第一个spark程序
  • vue脚手架vue-cli
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 如何在 Tornado 中实现 Middleware
  • 正则表达式
  • 交换综合实验一
  • # 安徽锐锋科技IDMS系统简介
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (java)关于Thread的挂起和恢复
  • (ros//EnvironmentVariables)ros环境变量
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • (转)visual stdio 书签功能介绍
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .NET Standard 的管理策略
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • .net经典笔试题
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • // an array of int
  • @PreAuthorize与@Secured注解的区别是什么?
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [Android]通过PhoneLookup读取所有电话号码
  • [Angular] 笔记 6:ngStyle
  • [autojs]autojs开关按钮的简单使用
  • [CTF]php is_numeric绕过
  • [C和指针].(美)Kenneth.A.Reek(ED2000.COM)pdf
  • [C语言]一维数组二维数组的大小
  • [Invalid postback or callback argument]昨晚调试程序时出现的问题,MARK一下