Java 9的这一基本功能,你可能从未听过

2017年7月即将发布的Java 9将会新增和修订不少功能和特性。在搜索JDK增强提议(JEP)时发现,JEP 266对CompletableFuture进行了一些有趣的改进,更新并发功能和支持Reactive Streams。

本文的焦点就是JEP 266的改进和一些有趣的特性,它极有可能成为Java 9中最常用的特性之一。

JEP 266改进计划

JEP 266是Oracle草拟JDK增强协议里面的一员,其中对并发进行了大量的更新。根据提案,将要进行更新的特性有:

  1. 支持Reactive Streams发布-订阅框架接口
  2. 对CompletableFuture API进行更新,例如支持延迟、超时、子类化和其它方法
  3. 其它一般改进,例如小调整和javadoc规范重写

本文重点关注前两个改进。首先,Java 9将支持Reactive Streams,这是一个来自Java社区的改进计划,旨在改进开发人员的并发工作流程。其次是CompletableFuture API提供的几个fixer-uppers,可以让开发人员回到Future<T>

Flow类

Reactive Streams发布-订阅框架里面将嵌套一个Flow类,以及开发人员可以用来创建自定义组件使用的SubmissionPublisher。

先从最上面的说起,Reactive Streams主要解决背压(back-pressure)问题。当传入的任务速率大于系统处理能力时,数据处理将会对未处理数据产生一个缓冲区。

与此同时,我们还与Akka团队的高级开发人员Konrad Malawski进行了沟通,他是Reactive Streams计划的领导者,解释了Reactive Streams的重要性以及如何使用。

Oracle指出,新的增强将包括“一个很小的接口,其定义符合(来自Reactive Stream initiative的)广泛参与”,这就是Flow类的来源。

Reactive Streams由4个Java接口构成:

  • 处理器(Processor)
  • 发布商(Publisher)
  • 订阅用户(Subscriber)
  • 订阅(Subscription)

Flow类允许相互关联的接口和静态方法来建立流控制组件,其中发布者产生由一个或多个订阅者消费的项目,每个订阅者由订阅管理。

Reactive Streams构建在java.util.concurrent.Flow容器对象下,开发者可以在这里找到Flow.Publisher,一个用作lambda表达式或方法引用的赋值目标功能接口。该接口可以让开发者更容易生成Flow.Subscription元素,并且将它们链接在一起。

另一个元素Flow.Subscriber,是异步工作机制,由请求触发。它可以从Flow.Subscription请求多个元素,开发者还可以根据需要自定义缓冲区大小。

这些接口适用于并发和分布式异步设置,它们之间的通信依赖于一种简单的流控制形式,可用于避免资源管理问题。

感兴趣的用户可以在java.util.concurrent.Flow下面查看代码示例。

目前已有一些第三方库实现了Reactive Streams接口,你无需等到Java 9发布便可尝试一下。

CompletableFuture新特性

Java 8引进了CompletableFuture,继承自Future<T>。Futures是非常有用的,当我们不希望或者不需要一个直接计算结果的时候,我们会收到一个Future对象来保存计算完成时分配的实际结果。通过调用complete()方法并且无需异步等待即可显式完成。它还允许在一系列操作中构建管道数据流程。

这样,任何类型的可用值都可以在Future中使用默认返回值,即使计算没有完成。这也将成为CompletableFuture提案更新的一部分,包括延迟和超时、更好地支持子类化和一些实用方法。

更多CompletableFuture功能改进和提案,大家可以前往这里查看。

总结

Java 9即将带来一些重大的更新与改进,其中JEP 266会是最有趣的一部分改进。它的改进方案主要来自社区的一些倡议,旨在帮助开发人员解决异步处理方面的一些重大问题。

原文The Essential Java 9 Feature You Probably Never Heard Of
作者Henn Idan 翻译:Daisy 责编:仲培艺

<think>我们正在讨论Android应用间广播监听的问题。根据提供的引用材料,我们可以总结以下几点关键信息: 1. 引用[1]介绍了如何通过广播接收器监听网络状态改变,包括创建BroadcastReceiver、重写onReceive()方法以及注册方式(静态和动态)。 2. 引用[2]指出,从Android 3.1开始,系统增加了对应用运行状态的跟踪。发送广播时,系统默认添加了FLAG_EXCLUDE_STOPPED_PACKAGES标志,这意味着即使静态注册的广播接收器,如果应用进程已退出,也无法接收到广播。 3. 引用[3]和[4]虽然提到了其他内容(如软键盘监听和应用前后台状态),但与应用间广播监听关系不大。 用户的问题:在个应用程序中监听另个应用程序的广播是否可行?如何实现? 回答思路: 1. 首先明确可行性:在Android中,应用间广播监听是可行的,但受到系统限制(特别是Android 3.1及以后版本)。 2. 实现方式:主要分为两种广播类型:普通广播和有序广播。另外,还可以使用LocalBroadcastManager(但仅限于应用内)。 3. 注意事项:包括权限设置、接收器的注册方式以及目标应用的状态(是否运行)对接收广播的影响。 详细步骤: - 发送广播的应用:需要发送个显式或隐式的广播。如果希望其他应用接收,通常使用隐式广播(指定action),但注意Android 8.0(API 26)以后对隐式广播的限制。 - 接收广播的应用:需要注册个BroadcastReceiver,并指定相同的action。注册方式可以是动态注册(在代码中注册)或静态注册(在AndroidManifest.xml中声明)。注意,静态注册在应用未启动时也能接收广播(但受Android 3.1及以上版本的限制,如果应用从未启动过则无法接收)。 针对Android 3.1及以上的限制(FLAG_EXCLUDE_STOPPED_PACKAGES): - 如果目标应用从未启动过(处于停止状态),则无法接收到广播。 - 解决方法:让目标应用至少启动次(用户手动启动或发送个带FLAG_INCLUDE_STOPPED_PACKAGES标志的广播,但该标志需要系统权限,普通应用无法使用)。 另外,Android 8.0(API 26)对隐式广播做了进步限制:除了少数例外,应用不能使用静态注册的接收器来接收隐式广播。因此,对于应用间广播,建议使用动态注册或使用显式广播(指定接收应用的包名或组件名)。 实现步骤示例: 1. 发送广播的应用(App A): ```java Intent intent = new Intent(); intent.setAction("com.example.MY_CUSTOM_ACTION"); // 自定义的action // 对于Android 8.0及以上,最好设置接收应用的包名(显式广播) // intent.setPackage("com.example.appb"); // 指定接收应用的包名,这样变成显式广播 sendBroadcast(intent); ``` 2. 接收广播的应用(App B): - 动态注册(在Activity或Service中): ```java BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // 处理广播 } }; IntentFilter filter = new IntentFilter("com.example.MY_CUSTOM_ACTION"); registerReceiver(receiver, filter); ``` 注意:动态注册的接收器只在注册的组件(如Activity)运行期间有效。 - 静态注册(在AndroidManifest.xml中): ```xml <receiver android:name=".MyReceiver" android:enabled="true" android:exported="true"> <!-- 允许接收其他应用的广播 --> <intent-filter> <action android:name="com.example.MY_CUSTOM_ACTION" /> </intent-filter> </receiver> ``` 注意:静态注册在应用未启动时也能接收广播,但受Android 3.1及以上版本的限制(应用必须至少启动次)以及Android 8.0对隐式广播的限制。 3. 权限问题(可选): - 如果广播包含敏感数据,可以设置权限。发送和接收广播时声明相同的权限。 总结可行性: - 如果两个应用都处于运行状态(或目标应用至少启动过次),则通过隐式广播可以实现应用间通信(但注意Android 8.0对静态注册接收隐式广播的限制)。 - 更好的做法是使用显式广播(指定包名),这样不受隐式广播限制的影响,但需要知道目标应用的包名。 - 对于需要后台持续监听的场景,静态注册的接收器可能无法在Android 8.0以上工作(隐式广播受限),此时可以考虑使用动态注册(但要求应用在运行)或使用JobScheduler等替代方案。 最后,生成相关问题。</think>### Android 应用间广播监听实现指南 在 Android 中,应用间广播监听**是可行的**,但需要满足特定条件。以下是关键实现步骤和注意事项: #### 、实现原理 1. **广播机制基础**: - 发送方应用通过 `sendBroadcast()` 发送包含特定 Action 的 Intent - 接收方应用注册匹配该 Action 的 BroadcastReceiver - 当发送广播时,系统自动匹配并触发接收方的 `onReceive()` 方法 2. **跨应用通信条件**: ```xml <!-- 接收方 AndroidManifest.xml 必须声明 --> <receiver android:name=".CustomReceiver" android:exported="true"> <!-- 关键!允许外部应用访问 --> <intent-filter> <action android:name="com.example.APP_SPECIFIC_ACTION" /> </intent-filter> </receiver> ``` #### 二、具体实现步骤 1. **发送方应用**: ```java // 发送跨应用广播 Intent broadcast = new Intent("com.example.APP_SPECIFIC_ACTION"); broadcast.putExtra("data", "Hello from App A!"); sendBroadcast(broadcast); ``` 2. **接收方应用**: ```java // 动态注册接收器(推荐) BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if ("com.example.APP_SPECIFIC_ACTION".equals(intent.getAction())) { String data = intent.getStringExtra("data"); // 处理接收到的数据 } } }; IntentFilter filter = new IntentFilter("com.example.APP_SPECIFIC_ACTION"); registerReceiver(receiver, filter); // 在Activity/Service中注册 ``` #### 三、关键限制与解决方案 1. **Android 3.1+ 限制**: - 系统默认添加 `FLAG_EXCLUDE_STOPPED_PACKAGES` 标志[^2] - **解决方案**:确保接收方应用至少启动过次(进程非停止状态) 2. **Android 8.0+ 隐式广播限制**: - 静态注册的接收器无法接收隐式广播[^2] - **解决方案**: ```java // 发送时指定接收方包名(显式广播) Intent broadcast = new Intent("com.example.APP_SPECIFIC_ACTION"); broadcast.setPackage("接收方包名"); // 突破限制的关键 sendBroadcast(broadcast); ``` 3. **权限控制**: ```xml <!-- 发送方需声明权限 --> <uses-permission android:name="接收方定义的权限"/> <!-- 接收方定义自定义权限 --> <permission android:name="com.example.BROADCAST_PERMISSION" android:protectionLevel="signature"/> <!-- 签名级更安全 --> ``` ```java // 发送带权限的广播 sendBroadcast(intent, "com.example.BROADCAST_PERMISSION"); ``` #### 四、最佳实践 1. **生命周期管理**: - 动态注册的接收器需在 `onDestroy()` 中调用 `unregisterReceiver()` - 避免在 `onReceive()` 执行超过10的操作,否则触发 ANR 2. **安全建议**: - 使用 `android:permission` 限制接收器访问 - 对传输数据做签名验证 - 敏感数据使用 `LocalBroadcastManager`(限于应用内) 3. **替代方案考虑**: - 跨进程通信推荐使用 AIDL 或 ContentProvider - 后台状态监听参考 `AppFrontBackHelper` 的实现[^4] > **可行性总结**:应用间广播监听在 Android 上完全可行,但需注意系统版本限制(尤其是 Android 8.0+),通过显式指定包名和权限控制可实现稳定通信。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值