MVVMCross Messenger - 订阅静态类中的消息

时间:2016-03-09 19:12:56

标签: c# xamarin xamarin.ios mvvmcross

我正在考虑实施MVVMCross Messenger解决方案,这样我就可以在从iOS应用程序或PCL发布时将信息上传到Google Analytics。

我遇到的问题是我发布后不会触发订阅delgates。你能订购静态类的MVVMCross Messenger订阅吗?

静态类中的订阅

objdump -p /path/to/program-or-library | grep NEEDED

公开

public static class GoogleAnalyticsWrapper //: IDisposable
{
    private const string TrackingId = "xxxxxxxxxxx";

    private static readonly IMvxMessenger messenger;
    private static readonly MvxSubscriptionToken screenNameToken;
    private static  readonly MvxSubscriptionToken eventToken;
    private static  readonly MvxSubscriptionToken exceptionToken;
    private static  readonly MvxSubscriptionToken performanceToken;
    private static  readonly MvxSubscriptionToken publishToken;
    private static  bool disposed = false;
    private static  SafeHandle handle;

    static GoogleAnalyticsWrapper()
    {
        Gai.SharedInstance.DispatchInterval = 60;
        Gai.SharedInstance.TrackUncaughtExceptions = true;

        Gai.SharedInstance.GetTracker(TrackingId); 

        messenger = new MvxMessengerHub();// Mvx.Resolve<IMvxMessenger>();
        screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));

        int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();

        eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
        exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
        performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
        publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
    }

    public static string Dummy { get; set; }

    public static void SetScreenName(GaScreenNameMessage message) 
    {
        System.Diagnostics.Debugger.Break();
        Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
        Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
    }

    public static  void CreateEvent(GaEventMessage message) 
        => Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());

    private static  void CreateException(GaExceptionMessage message) 
        => Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());

    private static  void CreatePerformanceMetric(GaPerformanceTimingMessage message)
        => Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());

    private static  void PublishAll(GaPublishMessage message) 
        => Gai.SharedInstance.Dispatch();

    public static  void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources.
                if (handle != null)
                {
                    handle.Dispose();
                }
            }

            // Dispose unmanaged managed resources.
            disposed = true;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

问题是,您在静态类中创建了一个新的MvxMessengerHub,但是(我猜)会在您的消费类中注入IMvxMessenger,这是由MvvMCross在初始化生命周期中因此是一个不同的实例。

简单的解决方案是在 App.cs 中初始化它,如

public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
    public override void Initialize()
    {
        // ...

        var m = Cirrious.CrossCore.Mvx.Resolve<IMvxMessenger>();
        GoogleAnalyticsWrapper.Initialize(m); 
        // ...
    }
}

使用这样的包装

public static class GoogleAnalyticsWrapper
{
    static void Initialize(IMvxMessenger messenger)
    {
        Gai.SharedInstance.DispatchInterval = 60;
        Gai.SharedInstance.TrackUncaughtExceptions = true;
        Gai.SharedInstance.GetTracker(TrackingId); 

        screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));

        int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();

        eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
        exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
        performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
        publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
    }

    // ...
}   

高级提示

但据我所知,你甚至不需要为这种情况发信息,因为这是一对一的“沟通”。如果您将GoogleAnalyticsWrapper的功能转移到定义良好的服务中,我认为这样会很好:

interface ITrackingService
{  
    void SetScreenName(GaScreenNameMessage message);
    void CreateEvent(GaEventMessage message);
    void CreateException(GaExceptionMessage message);
    void CreatePerformanceMetric(GaPerformanceTimingMessage message);
    void PublishAll(GaPublishMessage message);
}

public class GoogleAnalyticsTrackingService : ITrackingService
{
    private const string TrackingId = "xxxxxxxxxxx";

    public GoogleAnalyticsTrackingService()
    {
        Gai.SharedInstance.DispatchInterval = 60;
        Gai.SharedInstance.TrackUncaughtExceptions = true;

        Gai.SharedInstance.GetTracker(TrackingId);
    }

    public void SetScreenName(GaScreenNameMessage message) 
    {
        Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
        Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
    }

    public void CreateEvent(GaEventMessage message) 
    {
        Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
    }   

    private void CreateException(GaExceptionMessage message) 
    {
        Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
    }

    private void CreatePerformanceMetric(GaPerformanceTimingMessage message)
    {
        Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
    }

    private void PublishAll(GaPublishMessage message) 
    {
        Gai.SharedInstance.Dispatch();
    }
}

必须在您的应用程序中注册

Mvx.LazyConstructAndRegisterSingleton<ITrackingService, GoogleAnalyticsTrackingService>();

可以使用构造函数注入或手动解析

class MyViewModel : MvxViewModel 
{
    public MyViewModel(ITrackingService tracking)
    {
         tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
    }
}

// or
class MyViewModel : MvxViewModel 
{
    public MyViewModel()
    {
         var tracking = Mvx.Resolve<ITrackingService>();
         tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
    }
}

还有一个问题:界面仍然依赖谷歌分析。但是,通过使用多个参数而不是参数对象,可以轻松删除依赖关系。

interface ITrackingService
{
    void CreateEvent(string eventName, string title, string message, params object[] additionalParams);
    // ...
} 

// call:
tracking.CreateEvent("Event", "Publish Event", "Publish Event From First View Model", 123);

通过这种方式,如果您的利益相关者决定切换到adobe omniture或其他任何东西,您就可以对其进行单元测试并交换跟踪服务。