Android复习(Android基础-四大组件)——Service与Activity通信

  • 我们前面学会了启动和停止服务的方法,但是服务虽然是在活动里启动的,但是启动服务之后,活动与服务之间基本没什么关系了。
  • 正常情况,我们在Activity里调用startService()方法启动MyService这个服务,然后MyService的onCreate()和onStartCommand()方法就会得到执行。之后服务会一直处于运行状态,具体运行什么逻辑,活动控制不了
  • 如果我们想让活动和服务的关系更紧密一些。例如在活动中指挥服务去干什么,服务就去干什么。就要使用我们刚刚忽略的onBind()方法

1. 绑定服务

1.1 绑定服务的流程

  • 下面举一个例子:我们希望在MyService里实现一个下载功能,然后在Activity可以决定何时开始下载,以及随时查看下载的进度。
  • 我们可以专门创建一个Binder对象来对下载功能进行管理。
public class MyService extends Service {public MyService() {}class DownloadBinder extends Binder{public void startDownload(){Log.d("MyService", "startDownload executed");}public void getProgress(){Log.d("MyService", "getProgress execute");}}//一个Binder对象来对下载功能进行管理private DownloadBinder mBinder = new DownloadBinder();@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}
  • MainActivity中创建连接,调用bindService进行服务和Activity之间的绑定。
public class MainActivity extends AppCompatActivity {//1.获取Binderprivate MyService.DownloadBinder downloadBinder;//2.获取connectionprivate ServiceConnection connection = new ServiceConnection() {//这两个方法会在活动与服务成功绑定以及解除绑定前后调用@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {//向下转型获得mBinderdownloadBinder = (MyService.DownloadBinder) service;downloadBinder.startDownload();downloadBinder.getProgress();}@Overridepublic void onServiceDisconnected(ComponentName name) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent(this , MyService.class);bindService(intent , connection , BIND_AUTO_CREATE);unbindService(connection);}
}

1.2 绑定服务的相关知识点

  • IBinder

    1. 可以将多个客户端同时连接到某项Service。
    2. 系统会缓存IBinder服务通信通道。当第一个客户端绑定Service时,系统会调用onBind()方法生成IBinder。系统会将该IBinder传递给其他所有客户端(绑定了当前Service的)。无需再次调用onBind()
    3. 当最后一个客户端取消与Service的绑定时,系统会销毁该Service(除非还通过startService启动了当前Service)
  • bindService()

    1. bindService()的返回值指示所请求的Service是否存在,以及是否允许客户端访问该Service。
    2. 返回false,说明客户端与Service之间并无有效连接。不过,客户端仍然需要调用unbindService()。否则客户端会使Service无法在空闲时关闭。
  • Intent(第一个参数)

    1. 第一个参数是Intent,用来显示命名要绑定的Service。
    2. 隐式Intent启动Service存在安全隐患,让用户无法确定哪些服务器启动了。所以在Android5.0开始使用隐式Intent调用bindService()系统会抛出异常
  • ServiceConnection(第二个参数)

    1. 必须提供ServiceConnection的实现,用于监控与Service的连接。
    2. Android系统创建客户端与Service之间的连接时,会对ServiceConnection调用onServiceConnected()。onServiceConnected方法包含一个IBinder参数,客户端随后会使用该参数与绑定Service通信
  • 绑定选项的标记(第三个参数)

    1. 如果要创建尚未处于活动状态的Service,此参数通常为BIND_AUTO_CREATE。
    2. 其他可能的值为BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,或者0(表示无参数)

2. Service与Activity之间的通信

  1. 通过Binder进行通信
  2. 通过BroadCast
  3. 通过Messenger

2.1 Binder

  • 在Service中拓展Binder类,并从onBind()返回该类的实例。
  • 客户端收到Binder后,可以利用它直接访问 Binder实现 或 Service中提供的公共方法。

具体流程(代码见1.1)
1. 在Service中自定义一个Binder类,并创建可执行以下某种操作的Binder实例:

  • 包含Activity客户端可以调用的 public方法。
  • 返回当前的Service实例,该实例中包含客户端可调用的公共方法。
  • 返回由Service承载的其他类的实例,其中包含客户端可调用的公共方法。

2.从onBind()方法返回此Binder实例
3. 在客户端中,在ServiceConnection的onServiceConnected()回调方法中接收Binder,并使用提供的方法调用绑定Service。

  • 这样我们就可以通过这个Binder对象去调用我们定义的方法去控制Service。

代码2

  • LocalService(返回的是Service的实例,实例中包含客户端可以调用的方法getRandomNumber)
public class LocalService extends Service {private final IBinder binder = new LocalBinder();private final Random mGenerator = new Random();public class LocalBinder extends Binder {LocalService getService() {return LocalService.this;}}@Overridepublic IBinder onBind(Intent intent) {return binder;}public int getRandomNumber() {return mGenerator.nextInt(100);}
}
  • BindingActivity
public class BindingActivity extends Activity {LocalService mService;boolean mBound = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotected void onStart() {super.onStart();// 绑定服务Intent intent = new Intent(this, LocalService.class);bindService(intent, connection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();//解绑服务unbindService(connection);mBound = false;}public void onButtonClick(View v) {if (mBound) {int num = mService.getRandomNumber();Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();}}//连接,监听Serviceprivate ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className , IBinder service) {//向下转型获取Binder//获取ServiceLocalBinder binder = (LocalBinder) service;mService = binder.getService();mBound = true;}@Overridepublic void onServiceDisconnected(ComponentName arg0) {mBound = false;}};
}

2.2 Broadcast

  • 发送广播也可以实现Service和Activity的通信
  • 在服务里面发送广播
@Override
public int onStartCommand(Intent intent, int flags, int startId) {Log.d("Ning", "onStartCommand: ");Intent newIntent = new Intent();newIntent.putExtra("key" , "text");newIntent.setAction("location.report");sendBroadcast(newIntent);return super.onStartCommand(intent, flags, startId);
}
  • MainActivity中创建广播接收器
//内部类,实现BroadcastReceiver,创建内部类作为广播接收器
public class LocationReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {String intentAction = intent.getAction();if(intentAction.equals("location.report")){Log.d("Ning", "onReceive: 111111111");}}
}
  • onCreate注册广播和onDestroy注销广播
    LocationReceiver locationReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);locationReceiver = new LocationReceiver();IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("location.report");registerReceiver(locationReceiver , intentFilter);Log.d("Ning", "onReceive: 11111");Intent intent = new Intent(this , MyService.class);startService(intent);}@Overrideprotected void onDestroy() {unregisterReceiver(locationReceiver);super.onDestroy();}

2.3 使用Messenger

  • 如需让接口跨不同进程工作,可以使用Messenger为Service提供接口。
    • 这种方式,Service会绑定一个Handler,用于响应不同类型的Message对象。在Service中创建一个Messenger对象并绑定Handler,重写handler的handleMessage。
  • Messenger是执行进程间通信(IPC)最为简单的方式,因为Messenger会在单个线程中创建包含所有请求的队列,这样就不必对Service进行线程安全设计。
    在这里插入图片描述
public class MessengerService extends Service {static final int MSG_SAY_HELLO = 1;//1.实现IncomingHandler来接收客户端的每个回调static class IncomingHandler extends Handler{private Context applicationContext;IncomingHandler(Context context){applicationContext = context.getApplicationContext();}@Overridepublic void handleMessage(@NonNull Message msg) {switch (msg.what){case MSG_SAY_HELLO:Toast.makeText(applicationContext, "hello", Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);}}}Messenger mMessenger;@Nullable@Overridepublic IBinder onBind(Intent intent) {Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();//2.使用Handler创建Messenger对象,mMessenger = new Messenger(new IncomingHandler(this));//3.Messenger创建一个IBinderreturn mMessenger.getBinder();}
}
  • 接下来,Service会在Handler的handleMessage()方法中接收传入的Message,并根据what决定下一步操作。
  • 客户端只需根据Service返回的IBinder创建Messenger,使用send()发送消息。
public class ActivityMessenger extends Activity {Messenger mService = null;boolean bound;//连接//这里用和服务端一样的IBinder创建一个Messengerprivate ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {mService = new Messenger(service);bound = true;}public void onServiceDisconnected(ComponentName className) {mService = null;bound = false;}};//通过这个Messenger发送Messagepublic void sayHello(View v) {if (!bound) return;Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);try {mService.send(msg);} catch (RemoteException e) {e.printStackTrace();}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotected void onStart() {super.onStart();bindService(new Intent(this, MessengerService.class), mConnection,Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();if (bound) {unbindService(mConnection);bound = false;}}
}

3. 相关问题

3.1 Service中更新UI?

在这里插入图片描述

3.2 如何保证Service不被杀死?

在这里插入图片描述

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

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

相关文章

Games101学习笔记 - MVP矩阵

MV矩阵(模型视图变换) 目的,把摄像机通过变换移动的世界坐标远点,并且朝向与Z轴的负方向相同。这个变换就是模型试图变换。 因为移动了相机,如果想保持正确的渲染的话,那么对应的物体需要要和相机保持相对…

day23-113. 路径总和ii

113. 路径总和ii 力扣题目链接(opens new window) 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树,以及目标和 sum 22, 思路 利用…

机器学习(十八):Bagging和随机森林

全文共10000余字,预计阅读时间约30~40分钟 | 满满干货(附数据及代码),建议收藏! 本文目标:理解什么是集成学习,明确Bagging算法的过程,熟悉随机森林算法的原理及其在Sklearn中的各参数定义和使用方法 代码…

【Spring】Spring中的设计模式

文章目录 责任链模式工厂模式适配器模式代理模式模版方法观察者模式构造器模式 责任链模式 Spring中的Aop的通知调用会使用责任链模式责任链模式介绍 角色:抽象处理者(Handler)具体处理者(ConcreteHandler1)客户类角…

14.3.4 【Linux】使用 LVM thin Volume 让 LVM 动态自动调整磁盘使用率

想像一个情况,你有个目录未来会使用到大约 5T 的容量,但是目前你的磁盘仅有 3T,问题是,接下来的两个月你的系统都还不会超过 3T 的容量, 不过你想要让用户知道,就是他最多有 5T 可以使用就是了!…

Docker+rancher部署SkyWalking8.5并应用在springboot服务中

1.Skywalking介绍 Skywalking是一个国产的开源框架,2015年有吴晟个人开源,2017年加入Apache孵化器,国人开源的产品,主要开发人员来自于华为,2019年4月17日Apache董事会批准SkyWalking成为顶级项目,支持Jav…

Stable Diffusion - 俯视 (from below) 拍摄的人物图像 LoRA 与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132192139 图像来自 哥特风格 LoRA 俯视 LoRA&#xff0c;提升视觉冲击力&#xff0c;核心配置 <lora:view_from_below:0.6>,(from below,…

工程管理系统简介 工程管理系统源码 java工程管理系统 工程管理系统功能设计em

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff…

什么是进程、线程、协程

什么是进程&#xff1f; 我们都知道计算机的核心是CPU&#xff0c;它承担了所有的计算任务&#xff1b;而操作系统是计算机的管理者&#xff0c;它负责任务的调度、资源的分配和管理&#xff0c;统领整个计算机硬件&#xff1b;应用程序则是具有某种功能的程序&#xff0c;程序…

github上有哪些值得读源码的react项目?

前言 下面是我整理的关于值得一读源码的react项目&#xff0c;希望对你有所帮助~ 1、 calcom Star: 21.6k calcom是一个开源的计算器应用程序。它提供了基本的数学运算功能&#xff0c;例如加法、减法、乘法和除法&#xff0c;还支持 科学计算、进制转换和单位转换等高级功能…

【linux-keepalive】keepalive避免单点故障,高可用配置

keepalive: [rootproxy ~]# yum install -y keepalived [rootproxy ~]# vim /etc/keepalived/keepalived.conf global_defs {router_id proxy1 //设置路由ID号vrrp_iptables //不添加任何防火墙规则 } vrrp_instance V…

c语言每日一练(4)

五道选择题 1、有以下代码&#xff0c;程序的输出结果是( ) #include <stdio.h> int main() {int a 0, b 0;for (a 1, b 1; a < 100; a){if (b > 20) break;//1if (b % 3 1)//2{b b 3;continue;}b b-5;//3}printf("%d\n", a);return 0; } A.1…

【ARM Cache 系列文章 8 -- ARM DynamIQ 技术介绍

文章目录 DynamIQ 技术背景DynamIQ技术详解DynamIQ 与 big.LITTLEDynamIQ cluster 分类硬件支持 DynamIQ为什么适合人工智能&#xff1f; DynamIQ 技术背景 2017年3月21日下午&#xff0c;ARM在北京金隅喜来登酒店召开发布会&#xff0c;正式发布了全新的有针对人工智能及机器…

IDEA创建项目常见问题

1.IDEA修改maven路径无效 创建spring项目&#xff0c;Maven导入报错&#xff0c;无法正常导入jar报&#xff0c;发现setting中设置的maven路径不是自己下载的路径&#xff0c;修改后无效。运行之后maven路径又恢复为其默认的路径 解决方案&#xff1a; 删除.mvn文件&#xff0…

dinput8.dll导致游戏打不开的解决方法,快速修复dinput8.dll文件

当你尝试启动某个游戏时&#xff0c;如果遇到dinput8.dll文件缺失或损坏的错误提示&#xff0c;可能会导致游戏无法正常运行。dinput8.dll是DirectInput API的一部分&#xff0c;它提供了游戏手柄、键盘和鼠标等输入设备的支持。本文将详细介绍dinput8.dll的作用、导致游戏无法…

Spring BeanPostProcessor 接口的作用和使用

BeanPostProcessor 接口是 Spring 框架中的一个扩展接口&#xff0c;用于在 Spring 容器实例化、配置和初始化 bean 的过程中提供自定义的扩展点。通过实现这个接口&#xff0c;您可以在 bean 实例创建的不同生命周期阶段插入自己的逻辑&#xff0c;从而实现对 bean 行为的定制…

AI 降临!!!

人的记忆是脆弱的。因此&#xff0c;个人笔记成为了我们构建第二大脑和进行知识管理的重要手段。然而&#xff0c;人工智能的崛起&#xff0c;无疑改变了我们处理信息和知识的方式。作为一名长期关注笔记方法论和 AI 软件的「效率成瘾者」和「软件发烧友」&#xff0c;我深感此…

银河麒麟高级操作系统V10助力联通云建设打出组合拳

联通云基于“双引擎基座一云多芯”为不同行业场景提供可靠、高质量的应用上云服务。在核心代码进行了全面把控&#xff0c;定制多架构芯片应用适配模版&#xff0c;开发了计算、存储、网络、中间件等组件&#xff0c;全面适配自主化服务器和操作系统&#xff0c;提供云服务器、…

Python中的dataclass:简化数据类的创建

Python中的dataclass是一个装饰器&#xff0c;用于自动添加一些常见的方法&#xff0c;如构造函数、__repr__、__eq__等。它简化了创建数据类的过程&#xff0c;减少了样板代码&#xff0c;提高了代码的可读性和可维护性。有点类似java里面的Java Bean。 让我们看一个简单的例子…

Cortex-M3的双堆栈MSP和PSP(学习)

M3的栈&#xff0c;先进后出。 是局部变量内存的开销&#xff0c;函数的调用都离不开栈。 Cortex-M3内核使用了双堆栈&#xff0c;即MSP和PSP。 MSP&#xff1a;Main_Stack_Pointer&#xff0c;即主栈。 PSP&#xff1a;Process_Stack_Pointer&#xff0c;即任务栈。 SP&#…