如何使用dot42取消订阅活动

时间:2014-01-24 10:57:02

标签: dot42

我有一个名为“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环境下运行正常。

有关此行为的任何想法?这是正确的设计吗?

感谢

1 个答案:

答案 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点击此问题。