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.hqwc.cn/news/66803.html

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

相关文章

Linux:iptables防火墙

目录 绪论 1、防火墙 1.1 保护范围 1.2 网络协议划分 1.3 协议:tcp 1.4 四表 1.5 五链 1.6 iptables的规则 1.7 匹配顺序 流入本机:prerouting ------->iuput---------->用户进程(httpd服务)------请求--------响应--------->数据要返…

如何做好一名网络工程师?具备的技能有哪些?

支持属于网络工程师的工作范围的企业网络,此网络与支持它的铜或光纤基础架构一样性能良好。网络工程师及其布线厂区需要为支持最新网络技术做好准备。网络工程师作为任何性能问题的解决者,需要拥有必要的工具来确定问题所在 — 在网络中还是在其他地方。…

ABeam×Startup丨德硕管理咨询(深圳)创新研究团队前往灵境至维·既明科技进行拜访交流

近日,德硕管理咨询(深圳)(以下简称“ABeam-SZ”)创新研究团队一行前往灵境至维既明科技有限公司(以下简称“灵境至维”)进行拜访交流,探讨线上虚拟空间的商业模式。 现场合影 &…

PHP原生类

什么是php原生类 原生类就是php内置类&#xff0c;不用定义php自带的类&#xff0c;即不需要在当前脚本写出&#xff0c;但也可以实例化的类 我们可以通过脚本找一下php原生类 <?php $classes get_declared_classes(); foreach ($classes as $class) {$methods get_clas…

JZ38 字符串的排列

题目地址&#xff1a;字符串的排列_牛客题霸_牛客网 题目回顾&#xff1a; 解题思路&#xff1a; 这里用到了全排列和剪枝。 首先我们来说全排列&#xff0c;设置一个vis数组来记录当期元素是否被使用过&#xff0c;然后dfs遍历整个数组&#xff0c;列出所有符合条件的路径就是…

SCSS的基本用法

1、声明变量 $ 声明变量的符号 $ 下面这张图左半部分是scss的语法&#xff0c;右半部分是编译后的css。&#xff08;整篇文章皆是如此&#xff09; 2、默认变量 !default sass 的默认变量仅需要在值后面加上 !default 即可。 如果分配给变量的值后面添加了 !default 标志…

【MySQL】MySQL 数据类型

目录 1. tinyint 类型 2. bit 类型 3. 小数类型 1、float 类型 2、decimal 类型 3. 字符串类型 1、char 类型 2、varchar 类型 4. 日期类型 5. enum和set 1、枚举和集合类型语法 2、枚举和集合类型的查找 6、find_in_set 函数 写在最后&#xff1a; 1. tinyint …

2004-2021年全国31省市场分割指数数据(原始数据+计算过程+最终结果+方法说明)

2004-2021年全国31省市场分割指数数据&#xff08;原始数据计算过程最终结果方法说明&#xff09; 1、时间&#xff1a;2004-2021年 2、来源&#xff1a;统计年鉴和国家统计局 3、指标&#xff1a;市场分割指数、食品类商品零售价格指数&#xff08;上年100&#xff09;、饮料、…

2023年国赛数学建模思路 - 案例:FPTree-频繁模式树算法

文章目录 算法介绍FP树表示法构建FP树实现代码 建模资料 ## 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模式树算法&#xff0c…

Kafka基本概念

文章目录 概要整体架构broker和集群ProducerConsumer和消费者组小结 概要 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、分区的、多副本的、多生产者、多订阅者&#xff0c;基于 zookeeper协调的分布式日志系统&#xff08;也可以当做MQ系统&#xff09;&#xff…

一文解析超标量处理器

一、引言 处理器&#xff08;central process unit,简称CPU&#xff09;是手机的核心部件&#xff0c;其主要功能是取指令并译码执行。CPU主要包括控制器和运算器两个部件&#xff0c;它对在手机中的所有硬件资源&#xff08;如存储器&#xff0c;输入输出单元&#xff09;进行…

设计师常用的UI设计软件推荐

如今&#xff0c;随着互联网时代设计岗位的演变&#xff0c;近年来出现了一位新兴而受欢迎的专业UI设计师。对于许多对UI设计感兴趣或刚刚接触UI设计的初学者来说&#xff0c;他们不禁想知道&#xff0c;成为一名优秀的UI设计师需要掌握哪些UI软件&#xff1f;今天&#xff0c;…