Android Service

news/2024/9/19 13:29:21/文章来源:https://www.cnblogs.com/20lxj666/p/18400574

Android Service

参考:https://blog.csdn.net/javazejian/article/details/52709857

1、Service简单概述

Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行,Service基本上分为两种形式:

  • 启动状态

当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响,除非手动调用才能停止服务, 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

  • 绑定状态

当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

Service在清单文件中的声明

前面说过Service分为启动状态和绑定状态两种,但无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来,也都需要在AndroidManifest.xml中声明,那么在分析这两种状态之前,我们先来了解一下Service在AndroidManifest.xml中的声明语法,其格式如下:

<service android:enabled=["true" | "false"]android:exported=["true" | "false"]android:icon="drawable resource"android:isolatedProcess=["true" | "false"]android:label="string resource"android:name="string"android:permission="string"android:process="string" >. . .
</service>12345678910
  • android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
  • android:name:对应Service类名
  • android:permission:是权限声明
  • android:process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
  • android:isolatedProcess :设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。
  • android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。

2、示例

1. 最简单的Service

让我们从最基本的Service开始:

1.1 MyService.java

public class MyService extends Service {private static final String TAG = "MyService";private Handler handler;private Runnable runnable;private int count = 0;@Overridepublic void onCreate() {super.onCreate();// 初始化Handler和Runnable,用于每秒递增count并打印日志handler = new Handler(Looper.getMainLooper());runnable = new Runnable() {@Overridepublic void run() {count++;Log.d(TAG, "Count: " + count);handler.postDelayed(this, 1000);}};handler.post(runnable); // 启动任务}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return START_STICKY; // 服务在被系统杀掉后会重启}@Overridepublic void onDestroy() {super.onDestroy();handler.removeCallbacks(runnable); // 停止任务}@Overridepublic IBinder onBind(Intent intent) {return null; // 这个简单的服务不使用绑定}
}

1.2 注册服务

<service android:name=".service.MyService"/>

1.3 activity

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, MyService.class);startService(intent);}
}

1.4 解释

  • onCreate():初始化服务,启动一个每秒递增count的任务,并打印日志。
  • onStartCommand():定义服务的启动行为,这里返回START_STICKY,表示如果服务被系统杀掉,系统会尝试重新启动它。
  • onDestroy():停止任务,清理资源。
  • onBind():返回null,表示这是一个简单的、不可绑定的服务。

2. 绑定服务(Bound Service)

绑定服务允许客户端(如Activity)绑定到服务,并与之交互。绑定服务通常用于与应用组件进行长时间的交互。

2.1 MyBoundService.java

public class MyBoundService extends Service {private final IBinder binder = new LocalBinder();private int count = 0;private String logData = "Initial Data";public class LocalBinder extends Binder {public MyBoundService getService() {return MyBoundService.this;}}@Overridepublic IBinder onBind(Intent intent) {return binder; // 返回IBinder实例}public String getServiceData() {return logData + count;}public void setServiceData(String data) {this.logData = data;}@Overridepublic void onCreate() {super.onCreate();// 计数任务new Handler(Looper.getMainLooper()).postDelayed(() -> {count++;Log.d("MyBoundService", "Count: " + count);}, 1000);}
}

2.2 注册服务

<service android:name=".service.MyBoundService" />

2.3 activity

public class MainActivity extends AppCompatActivity {private MyBoundService myBoundService;private boolean isBound = false;private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {MyBoundService.LocalBinder binder = (MyBoundService.LocalBinder) service;myBoundService = binder.getService();isBound = true;Log.d("MainActivity", "Service Connected: " + myBoundService.getServiceData());}@Overridepublic void onServiceDisconnected(ComponentName arg0) {isBound = false;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this, MyBoundService.class);bindService(intent, connection, Context.BIND_AUTO_CREATE);Handler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {myBoundService.setServiceData("Service finish");Log.d("MainActivity", "Service getLogData: " + myBoundService.getServiceData());// 执行延时后的UI更新任务System.exit(0);}}, 5000); // 延时5秒}@Overrideprotected void onDestroy() {super.onDestroy();if (isBound) {unbindService(connection);isBound = false;}}
}

2.4 解释

  • LocalBinder:定义一个内部类,用于客户端绑定服务时获取服务实例。
  • getServiceData():提供获取服务数据的接口。
  • setServiceData():提供设置服务数据的接口。

3.使用 Messenger 进行进程间通信(IPC)

Messenger需要结合Handler一起使用。需要一个handler,一个Messenger对象。handler最终会负责发送和接收消息。它不仅能够在后台执行任务,还能通过 Messenger 发送和接收消息,从而与客户端进行双向交互。

3.1 MyComplexService

public class MyComplexService extends Service {private static final String TAG = "MyComplexService";private final Messenger serviceMessenger = new Messenger(new IncomingHandler());private Messenger clientMessenger;private boolean isRunning = false;int count = 0;@Overridepublic IBinder onBind(Intent intent) {return serviceMessenger.getBinder(); // 返回Messenger的Binder}@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "Service created");}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "Service destroyed");isRunning = false; // 停止任务}private void startBackgroundTask() {if (isRunning) return;isRunning = true;// 后台线程开始计数任务new Thread(() -> {while (isRunning) {try {Thread.sleep(1000);count++;if (clientMessenger != null) {Message msg = Message.obtain(null, 0);Bundle bundle = new Bundle();bundle.putInt("count", count);msg.setData(bundle);try {clientMessenger.send(msg); // 发送消息给客户端} catch (RemoteException e) {e.printStackTrace();}}} catch (InterruptedException e) {e.printStackTrace();}}}).start();}// 处理客户端发送的消息private class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 1: // 客户端请求启动任务startBackgroundTask();break;case 2: // 客户端请求停止任务isRunning = false;stopSelf();break;case 3: // 客户端传递自己的MessengerclientMessenger = new Messenger(msg.replyTo.getBinder());break;default:super.handleMessage(msg);}}}
}

3.2 注册服务

<service android:name=".service.MyComplexService" />

3.3 activity

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private Messenger serviceMessenger;private boolean isBound = false;private TextView textView;private final Messenger clientMessenger = new Messenger(new IncomingHandler());private final ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {serviceMessenger = new Messenger(service);isBound = true;Message msg = Message.obtain(null, 3);msg.replyTo = clientMessenger;try {serviceMessenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName arg0) {serviceMessenger = null;isBound = false;}};private class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {int count = msg.getData().getInt("count");textView.setText("Count: " + count);}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = findViewById(R.id.textView);Intent intent = new Intent(this, MyComplexService.class);bindService(intent, connection, Context.BIND_AUTO_CREATE);findViewById(R.id.startButton).setOnClickListener(v -> startServiceTask());findViewById(R.id.stopButton).setOnClickListener(v -> stopServiceTask());}private void startServiceTask() {if (isBound) {Message msg = Message.obtain(null, 1);try {serviceMessenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}}private void stopServiceTask() {if (isBound) {Message msg = Message.obtain(null, 2);try {serviceMessenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}}@Overrideprotected void onDestroy() {super.onDestroy();if (isBound) {unbindService(connection);isBound = false;}}
}

3.4 解释

  • Messenger:用于在进程间传递消息。
  • IncomingHandler:处理来自服务的消息。

4. 使用AIDL进行跨进程通信(复杂)

允许多个客户端通过消息通信与服务进行复杂交互。在客户端(如Activity)中,通过ServiceConnection来绑定服务,并使用AIDL接口与服务通信。

4.1 MyBinderService.java

public class MyBinderService extends Service {private boolean isRunning = false;private int count = 0;private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {@Overridepublic void startTask() throws RemoteException {startBackgroundTask();}@Overridepublic void stopTask() throws RemoteException {stopBackgroundTask();stopSelf();}@Overridepublic int getCount() throws RemoteException {return count;}};@Overridepublic IBinder onBind(Intent intent) {return mBinder; // 返回AIDL接口的Binder实例}private void startBackgroundTask() {if (isRunning) return;isRunning = true;new Thread(() -> {while (isRunning) {try {Thread.sleep(1000);count++;Log.d("MyBinderService", "Count: " + count);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}private void stopBackgroundTask() {isRunning = false;}
}

4.2 注册服务

 <serviceandroid:name=".service.MyBinderService"android:exported="true"android:permission="android.permission.BIND_AUTO_CREATE" />

4.3 activity

public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private IMyAidlInterface mService;private boolean isBound = false;private TextView textView;private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {mService = IMyAidlInterface.Stub.asInterface(service);isBound = true;}@Overridepublic void onServiceDisconnected(ComponentName arg0) {mService = null;isBound = false;}};private Handler handler;private Runnable runnable;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = findViewById(R.id.textView);Intent intent = new Intent(this, MyBinderService.class);bindService(intent, mConnection, Context.BIND_AUTO_CREATE);Button startButton = findViewById(R.id.startButton);Button stopButton = findViewById(R.id.stopButton);startButton.setOnClickListener(v -> startServiceTask());stopButton.setOnClickListener(v -> stopServiceTask());handler = new Handler(Looper.getMainLooper());runnable = new Runnable() {@Overridepublic void run() {int count = 0;try {count = mService.getCount();Log.d(TAG, "run: count-->"+count);} catch (Exception e) {e.printStackTrace();}textView.setText("Count: " + count);handler.postDelayed(this, 1000);}};}private void startServiceTask() {if (isBound) {Log.d(TAG, "Start button clicked");try {mService.startTask();handler.removeCallbacks(runnable);handler.post(runnable);} catch (RemoteException e) {e.printStackTrace();}}}private void stopServiceTask() {if (isBound) {Log.d(TAG, "Stop button clicked");try {mService.stopTask();handler.removeCallbacks(runnable);} catch (RemoteException e) {e.printStackTrace();}}}@Overrideprotected void onDestroy() {super.onDestroy();if (isBound) {unbindService(mConnection);isBound = false;}}
}

4.4 解释

  • AIDL接口:IMyAidlInterface.Stub是AIDL接口的具体实现。它定义了可以由客户端调用的方法,如startTask()stopTask()getCount()

  • 服务在被绑定后,客户端可以通过这个接口与服务通信,执行跨进程任务。

  • ServiceConnection:用于管理客户端与服务的连接状态。

  • startServiceTask()stopServiceTask():通过AIDL接口启动和停止服务任务。

总结

  1. 简单的服务:适用于后台执行不需要与客户端交互的任务。
  2. 绑定服务:适用于需要与客户端交互的任务,客户端可以通过绑定服务获取数据或执行操作。
  3. message:适合于需要在服务和客户端之间传递消息的场景。
  4. AIDL服务:适用于跨进程通信场景,允许客户端与服务进行复杂的数据交互和任务管理。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

凡人歌:平凡公司的技术面试

我们见惯了大厂刷题面试宝典,大佬们只招世界上最优秀的人新闻。我们也乐见这些金字塔顶端给大家洒下的热点鸡汤。而现实却是平凡的小公司才是主流。我们见惯了大厂刷题面试宝典,大佬们只招世界上最优秀的人新闻。我们也乐见这些金字塔顶端给大家洒下的热点鸡汤。而现实却是平…

攻防世界 ————新手模式适合作为桌面 misc

(本篇文章参考大佬的解题) 下载附件,得到rar的的压缩包,解压缩,打开文件后有一张图片:打开图片发现什么也没有:使用软件Stegsolve打开图片看有什么问题:点击下一页:点击后发现有一个二维码:把他保存下来,使用软件扫码看看里面有什么: (我是用微信扫码的) 出现了十…

代码整洁之道--读书笔记(11)

代码整洁之道简介: 本书是编程大师“Bob 大叔”40余年编程生涯的心得体会的总结,讲解要成为真正专业的程序员需要具备什么样的态度,需要遵循什么样的原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来者引路,助其职业生涯迈上更…

Win7玩游戏Ctrl和空格不能一起按的解决方案

前几天在Windows7上玩《Minecraft》的时候,发现Ctrl和空格不能一起按,就开始研究,找到一个解决方案。 首先打开控制面板,点击更改键盘或其他输入法,就会进入文本服务与输入语言。点击更改键盘,进入高级键设置选项卡,点击下面的快捷键,再点击更改按键顺序。如图,随便把…

深度学习 初识学习 9.16

什么是SVM SVM(Support Vector Machine,支持向量机)是一种监督学习模型,用于分类和回归分析。其基本思想是找到一个超平面,使得两类样本在该超平面上的间隔最大化。这个间隔被称为“最大间隔”,而位于最大间隔边界上的样本点则被称为“支持向量”。 SVM的关键概念:超平面…

C++信奥老师解一本通题 1370:最小函数值(minval)

​ 【题目描述】有n个函数,分别为F1,F2,...,Fn。定义Fi(x)=Ai*x*x+Bi*x+Ci(x∈N∗)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的mm个(如有重复的要输出多个)。【输入】第一行输入两个正整数n和m。 以下nn行每行三个正整数,其中第ii行的三个数分别位Ai、Bi和C…

反DDD模式之关系型数据库

本文书接上回《图穷匕见-所有反DDD模式都是垃圾》,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新; DDD框架源码(.NET、Java双平台); 加群畅聊,建模分析、技术实现交流; 视频和直播在B站。 背景 我在与开发者交流关于DDD的建模思路时,往往会遇到一个难题,就是…

常回家看看之house_of_catWO

house_of_cat 前言: house of cat 这个利用手法和前面提到的 house of kiwi ,和 house of emma 利用的手法是一个链子,当程序无法通过main函数返回时候,或者程序不能显性调用exit函数的时候,我们可以通过 __malloc_assert 来刷新IO流,当然这个函数在2.35之后移除了刷新IO…

C++11 线程同步接口std::condition_variable和std::future的简单使用sk

合集 - C++(1)1.C++11 线程同步接口std::condition_variable和std::future的简单使用09-17收起 std::condition_variable 条件变量std::condition_variable有wait和notify接口用于线程间的同步。如下图所示,Thread 2阻塞在wait接口,Thread 1通过notify接口通知Thread 2继续执…

安全:nftables:基础知识

一,policy: 1,原文档链接: https://docs.redhat.com/zh_hans/documentation/red_hat_enterprise_linux/9/html/configuring_firewalls_and_packet_filters/assembly_creating-and-managing-nftables-tables-chains-and-rules_getting-started-with-nftables#con_basics-of-nft…

Leetcode 952. 按公因数计算最大组件大小

1.题目基本信息 1.1.题目描述 给定一个由不同正整数的组成的非空数组 nums ,考虑下面的图: 有 nums.length 个节点,按从 nums[0] 到 nums[nums.length - 1] 标记;只有当 nums[i] 和 nums[j] 共用一个大于 1 的公因数时,nums[i] 和 nums[j]之间才有一条边。 返回 图中最大连…

Leetcode 19.删除链表的倒数第第N个结点

1.题目基本信息 题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 地址:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/description/ 2.解题方法 2.1.解题思路 使用快慢指针 2.2.解题步骤 第一步,初始化快指针为head,慢指针指向一…