У меня есть статический класс под названием «BatteryManagerHelper», который контролирует состояние батареи с помощью намерения Intent.ACTION_BATTERY_CHANGED. Каждый раз, когда система уведомляет об изменении состояния батареи, мой класс улавливает изменения, сохраняет новые значения в общедоступных свойствах класса (заряд, статус, healt ..), затем поднимает событие «Изменено»Отказаться от подписки на мероприятие с dot42
общественное статическое событие Действие Изменено;
Каждая активность или класс в моем проекте могут подписаться на это событие с кодом:
BatteryManagerHelper.Changed += BatteryManagerHelper_Changed;
private void BatteryManagerHelper_Changed()
{
imgBattery.SetImageResource(some_resource);
}
он работает отлично.
Однако, когда действие происходит в OnPause() или OnDestory(), я хотел бы отказаться от подписки на событие Change, поэтому больше никаких уведомлений о моей деятельности.
Я попытался с
BatteryManagerHelper.Changed -= BatteryManagerHelper_Changed;
и
BatteryManagerHelper.Changed -= null;
и
BatteryManagerHelper.Changed += null;
, но никто не похоже на работу. Я получаю событие также в Деятельности был разрушен из системы.
Итак, первый вопрос: как правильно отписаться от событий? Второй вопрос: почему разрушенное действие может продолжать получать события?
Примечание: код подписки и отписки находится на OnResume() и OnPause(). Когда действие приостановлено, возобновлено, я получаю два уведомления о событиях; на паузе паузы-возобновления я получаю три последовательных уведомления и так далее. Кажется, что + = добавляет новый прослушиватель событий, а - = не может удалить слушателя, сохраняя предыдущие ссылки слушателей в игре.
Это статический код класса. Я использовал статический класс, чтобы он мог быть доступен в любом месте кода. Статический класс имеет (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();
}
}
}
}
Это код в моем фрагменте (этот фрагмент является заменой системы Toolbar, мое приложение является полноэкранным один), но вы также можете попробовать в классическом классе активность, о событиях 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 работает нормально.
Есть идеи по этому вопросу? Это правильно по дизайну?
благодаря
Можете ли вы показать нам, где вы подписались и отписаться? Возможно, вы успешно отменили подписку, но новый экземпляр повторно подписался, например. в вашем OnCreate. –
Привет, Франк, я улучшил свой пост с полным кодом. Вы можете попробовать самостоятельно мой статический класс с простой Activity и получить то же самое поведение: каждый новый + = добавляет новый listner правильно, но каждый - = не удаляет предыдущий справочник listner. – minimega