Learning Perl: 4.2. Invoking a Subroutine

Previous Page
Next Page

 

4.2. Invoking a Subroutine

Invoke a subroutine from within any expression by using the subroutine name (with the ampersand):[§]

[§] And frequently a pair of parentheses, even if empty. As written, the subroutine inherits the caller's @_ value, which we'll be discussing shortly. So don't stop reading here, or you'll be writing code with unintended effects.

    &marine;  # says Hello, sailor number 1!
    &marine;  # says Hello, sailor number 2!
    &marine;  # says Hello, sailor number 3!
    &marine;  # says Hello, sailor number 4!

Most often, we refer to the invocation as calling the subroutine.

Previous Page
Next Page
03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: exception when invoking removeOnUidImportanceListener 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: java.lang.IllegalArgumentException: Listener not registered: com.android.bluetooth.le_scan.ScanManager$2@a5c7225 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at android.app.ActivityManager.removeOnUidImportanceListener(ActivityManager.java:4734) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.le_scan.ScanManager.cleanup(ScanManager.java:329) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.le_scan.TransitionalScanHelper.cleanup(TransitionalScanHelper.java:283) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.gatt.GattService.cleanup(GattService.java:407) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.btservice.AdapterService.stopGattProfileService(AdapterService.java:1284) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.btservice.AdapterService.bringDownBle(AdapterService.java:1173) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.bluetooth.btservice.AdapterState$TurningBleOffState.enter(AdapterState.java:430) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.internal.util.StateMachine$SmHandler.invokeEnterMethods(StateMachine.java:1042) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.internal.util.StateMachine$SmHandler.performTransitions(StateMachine.java:888) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at com.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:828) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at android.os.Handler.dispatchMessage(Handler.java:112) 03-16 12:32:57.511 18324 18324 W BtGatt.ScanManager: at android.os.Looper.loopOnce(Looper.java:288) 帮我解决下这个报错
最新发布
03-19
<think>好的,我现在要解决用户提到的Android蓝牙BLE扫描管理器中出现的removeOnUidImportanceListener异常问题,具体是IllegalArgumentException,提示“listener not registered”。用户希望知道如何解决这个问题。首先,我需要理解这个异常产生的原因,以及如何避免它。 根据用户提供的引用内容,特别是引用[3],里面提到了动态注册的广播如果没有注销会导致内存泄漏,并且系统会报错“Receiver not registered”。这可能与当前的问题类似。虽然问题不是直接关于广播接收器,而是关于监听器的注册与注销,但原理应该是相同的:即尝试移除一个未注册的监听器会导致异常。 接下来,我需要分析用户可能在哪里使用removeOnUidImportanceListener。在Android的蓝牙BLE扫描中,可能涉及到注册和注销与UID重要性相关的监听器,用于管理扫描行为,比如在应用进入后台时停止扫描以节省资源。如果在调用removeOnUidImportanceListener时,监听器尚未注册或已经被移除,就会抛出IllegalArgumentException。 解决方案的核心应该是确保在移除监听器之前,它已经被正确注册,并且在适当的时候成对调用注册和移除方法。此外,需要处理可能的多线程或生命周期问题,例如在Activity或Service的onDestroy中移除监听器时,确保此时监听器仍然存在。 接下来,我需要查阅相关的Android文档或源代码,确认ScanManager中addOnUidImportanceListener和removeOnUidImportanceListener的使用方式。假设这些方法的调用类似于广播接收器的注册与注销,必须成对出现,否则会导致异常。 根据引用[1]中的代码,在JNI层注册扫描器时,会传递一个回调函数。这可能涉及到监听器的注册,但用户的问题是关于移除监听器的异常,所以需要关注Java层的管理部分。 可能的解决步骤包括: 1. 检查代码,确保每次调用removeOnUidImportanceListener之前,对应的监听器已经通过addOnUidImportanceListener注册。 2. 使用一个标志位或集合来跟踪监听器的注册状态,避免重复注册或重复移除。 3. 在组件(如Activity或Service)的生命周期方法中,确保在销毁时正确注销监听器,但在此之前检查是否已经注册。 4. 使用try-catch块来捕获异常,防止应用崩溃,但这只是临时解决方案,更好的做法是预防异常的发生。 例如,在代码中添加一个布尔变量来跟踪监听器是否被注册,然后在移除之前检查该变量。或者在注册时将监听器实例保存起来,移除时检查是否存在。 参考引用[3]的处理方式,动态注册的广播必须在不需要时注销,且必须成对存在。同样的逻辑适用于监听器的注册与移除。因此,用户需要确保在调用remove方法时,监听器已经被正确注册,并且没有被提前移除或从未注册过。 总结解决方案的关键点: - 确保add和remove方法成对调用。 - 在移除前检查监听器是否已注册。 - 使用适当的结构管理监听器的状态。 - 处理组件的生命周期,避免在监听器已被移除后再次调用移除方法。 最后,用户可能需要检查他们的代码逻辑,确认在哪些地方调用了add和remove方法,是否存在漏掉注册的情况,或者在生命周期结束时未正确注销。同时,参考Android官方文档或相关社区资源,确认是否有已知的问题或最佳实践。</think>### Android蓝牙BLE ScanManager中removeOnUuidImportanceListener异常解决方案 #### 问题原因 当调用$ScanManager.removeOnUidImportanceListener()$时抛出$IllegalArgumentException: listener not registered$,通常是因为: 1. **未成对调用注册/注销方法**:尝试移除未注册的监听器 2. **生命周期管理不当**:组件销毁时重复调用移除方法 3. **多线程竞争**:监听器被移除后再次调用移除操作[^3] --- #### 解决方案步骤 1. **检查注册状态** ```java // 使用标志位跟踪状态 private boolean isListenerRegistered = false; void registerListener() { if (!isListenerRegistered) { scanManager.addOnUidImportanceListener(listener); isListenerRegistered = true; } } void unregisterListener() { if (isListenerRegistered) { scanManager.removeOnUidImportanceListener(listener); isListenerRegistered = false; } } ``` 2. **生命周期绑定** ```java // 在Activity/Fragment的onDestroy中统一处理 @Override protected void onDestroy() { try { if (scanManager != null && listener != null) { scanManager.removeOnUidImportanceListener(listener); } } catch (IllegalArgumentException e) { Log.w(TAG, "Listener already unregistered", e); } super.onDestroy(); } ``` 3. **使用安全移除方法** ```java // 包装移除操作 public void safeRemoveListener(ScanManager manager, OnUidImportanceListener listener) { try { manager.removeOnUidImportanceListener(listener); } catch (IllegalArgumentException e) { // 已处理未注册情况 } } ``` --- #### 关键注意事项 1. **单例模式管理**:通过单例类统一管理所有监听器的注册状态 2. **弱引用持有**:使用$WeakReference$避免内存泄漏 ```java private WeakReference<OnUidImportanceListener> weakListener; ``` 3. **文档验证**:检查系统API是否要求必须在UI线程操作(如蓝牙相关API通常需要主线程)[^1] --- #### 优化建议 1. 使用AndroidX的$LifecycleObserver$自动绑定生命周期 ```java lifecycle.addObserver(new DefaultLifecycleObserver() { @Override public void onDestroy(@NonNull LifecycleOwner owner) { safeRemoveListener(); } }); ``` 2. 通过AOP(面向切面编程)实现自动注册/注销监控 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值