我有一个名为“BatteryManagerHelper”的静态类,它通过Intent.ACTION_BATTERY_CHANGED意图监视电池状态。每次系统通知电池状态的变化时,我的班级会捕捉到更改,将新值存储在类公共属性中(费用,状态,健康......)然后引发事件“已更改”
公共静态事件已更改操作;
我的项目中的每个Activity或Class都可以使用代码订阅此事件:
BatteryManagerHelper.Changed += BatteryManagerHelper_Changed;
private void BatteryManagerHelper_Changed()
{
imgBattery.SetImageResource(some_resource);
}
它工作正常。
但是当Activity进入OnPause()或OnDestory()时,我想取消订阅Change事件,因此不再向我的Activity发出通知。
我试过
BatteryManagerHelper.Changed -= BatteryManagerHelper_Changed;
和
BatteryManagerHelper.Changed -= null;
和
BatteryManagerHelper.Changed += null;
但似乎没有人工作。我在活动中也得到了活动已经从系统中销毁。
所以,第一个问题是:如何正确取消订阅活动? 第二个问题是:为什么被破坏的活动可以继续接收事件?
注意:订阅和取消订阅代码放在OnResume()和OnPause()上。暂停活动然后恢复我收到两个事件通知;在tirth pause-resume我得到三个连续的通知,依此类推。似乎+ =正在添加一个新的事件监听器,而 - =无法删除监听器,保留以前的监听器引用。
这是静态类代码。我使用了静态类,因此可以在代码中的任何位置访问它。静态类(obviuslly)是BroadcastReceiver回调的子类的私有实例。
using Android.Content;
using Android.Os;
using System;
namespace MenuDroidApp
{
public static class BatteryManagerHelper
{
private static BatteryBroadcastReceiverHelper batteryBroadcastReceiver = null;
private static Intent batteryStatusIntent = null;
public static event Action Changed;
public enum HealthEnum
{
Unknown = 1, // BATTERY_HEALTH_UNKNOWN
Good, // BATTERY_HEALTH_GOOD
OverHeat, // BATTERY_HEALTH_OVERHEAT
Dead, // BATTERY_HEALTH_DEAD
OverVoltage, // BATTERY_HEALTH_OVER_VOLTAGE
UnspecifiedFailure, // BATTERY_HEALTH_UNSPECIFIED_FAILURE
Cold, // BATTERY_HEALTH_COLD
}
public enum PluggedEnum
{
NotPlugged = 0,
PluggedAC, // BATTERY_PLUGGED_AC
PluggedUSB, // BATTERY_PLUGGED_USB
PluggedWireless, // BATTERY_PLUGGED_WIRELESS
}
public enum StatusEnum
{
Unknown = 1, // BATTERY_STATUS_UNKNOWN
Charging, // BATTERY_STATUS_CHARGING
Discharging, // BATTERY_STATUS_DISCHARGING
NotCharging, // BATTERY_STATUS_NOT_CHARGING
Full, // BATTERY_STATUS_FULL
}
public static int Charge { get; set; }
public static StatusEnum Status { get; set; }
public static PluggedEnum Plugged { get; set; }
public static HealthEnum Health { get; set; }
public static bool Present { get; set; }
public static string Technology { get; set; }
public static int Temperature { get; set; }
public static int Voltage { get; set; }
public static int IconResID { get; set; }
static BatteryManagerHelper()
{
batteryBroadcastReceiver = new BatteryBroadcastReceiverHelper();
batteryBroadcastReceiver.Changed += batteryBroadcastReceiver_Changed;
}
private static void batteryBroadcastReceiver_Changed()
{
if (Changed != null) Changed();
}
public static void Start()
{
batteryStatusIntent = Common.ApplicationContext.RegisterReceiver(batteryBroadcastReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
batteryBroadcastReceiver.GetBatteryInfo(batteryStatusIntent);
}
public static void Stop()
{
Common.ApplicationContext.UnregisterReceiver(batteryBroadcastReceiver);
batteryStatusIntent = null;
}
private class BatteryBroadcastReceiverHelper : BroadcastReceiver
{
public event Action Changed;
public override void OnReceive(Context context, Intent intent)
{
GetBatteryInfo(intent);
}
public void GetBatteryInfo(Intent intent)
{
BatteryManagerHelper.Charge = intent.GetIntExtra(BatteryManager.EXTRA_LEVEL, -1);
BatteryManagerHelper.Status = (StatusEnum)intent.GetIntExtra(BatteryManager.EXTRA_STATUS, 0);
BatteryManagerHelper.Health = (HealthEnum)intent.GetIntExtra(BatteryManager.EXTRA_HEALTH, 0);
BatteryManagerHelper.Plugged = (PluggedEnum)intent.GetIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
BatteryManagerHelper.Present = intent.GetBooleanExtra(BatteryManager.EXTRA_PRESENT, false);
BatteryManagerHelper.Technology = intent.GetStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
BatteryManagerHelper.Temperature = intent.GetIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1);
BatteryManagerHelper.Voltage = intent.GetIntExtra(BatteryManager.EXTRA_VOLTAGE, -1);
BatteryManagerHelper.IconResID = intent.GetIntExtra(BatteryManager.EXTRA_ICON_SMALL, -1);
if (Changed != null) Changed();
}
}
}
}
这是我的片段中的代码(这个片段是系统工具栏的替代品,我的应用程序是全屏的),但您也可以尝试使用经典的Activity类,关于事件OnResume()和OnPause()
public override void OnAttach(Activity activity)
{
BatteryManagerHelper.Changed += BatteryManagerHelper_Changed;
}
public override void OnDetach()
{
BatteryManagerHelper.Changed -= BatteryManagerHelper_Changed;
}
private void BatteryManagerHelper_Changed()
{
imgBattery.SetImageResource(some_resource_id);
}
好的,我在订阅/取消订阅活动时尝试了不同的方法:
private Action batteryManager_Callback = null;
public override void OnResume()
{
base.OnResume();
batteryManager_Callback = new Action(BatteryManagerHelper_Changed);
BatteryManagerHelper.Changed += batteryManager_Callback;
}
public override void OnPause()
{
base.OnPause();
BatteryManagerHelper.Changed -= batteryManager_Callback;
}
private void BatteryManagerHelper_Changed()
{
imgBattery.SetImageResource(some_res_id);
}
现在它运作正常。我为每个OnResume活动事件使用一个新的委托对象,并使用该委托订阅BatteryManager事件。委托引用也存储在私有类成员中。当我想取消订阅时,我使用在OnResumed()中创建的相同的原始委托引用,并且我确信将从事件侦听器队列中删除相同的一个特定委托。
所以看来原始代码
public override void OnAttach(Activity activity)
{
BatteryManagerHelper.Changed += BatteryManagerHelper_Changed;
}
public override void OnDetach()
{
BatteryManagerHelper.Changed -= BatteryManagerHelper_Changed;
}
对回调函数的引用BatteryManagerHelper_Changed()在+ =和=的时刻是不同的。但是Activity类实例是一样的,这很奇怪..这个例子在C#/ .NET环境下运行正常。
有关此行为的任何想法?这是正确的设计吗?
感谢
答案 0 :(得分:1)
编译此代码时:
private void BatteryManagerHelper_Changed()
{
imgBattery.SetImageResource(some_res_id);
}
BatteryManagerHelper.Changed += BatteryManagerHelper_Changed;
然后rhs不是委托类型,它将隐含地被Action实例包装。取消订阅时会发生同样的情况:
BatteryManagerHelper.Changed -= BatteryManagerHelper_Changed;
执行此操作时不会发生此隐式换行:
batteryManager_Callback = new Action(BatteryManagerHelper_Changed);
...
BatteryManagerHelper.Changed += batteryManager_Callback;
...
BatteryManagerHelper.Changed -= batteryManager_Callback;
由于包装,事件处理程序不会被视为相同的实例。
虽然这解释了你所看到的,但这不是正确的行为。它将在下一个版本中修复。
更新
您可以在https://github.com/dot42/dot42/issues/13点击此问题。