【问题标题】:Share data between main app and periodic task在主应用程序和周期性任务之间共享数据
【发布时间】:2012-08-26 18:56:54
【问题描述】:

我在无法解决的other one 之后发布了这个特定问题。

简而言之:即使我创建了一个静态类(带有静态变量和/或属性),主应用程序和后台代理也不使用相同的静态类,而是都创建了它的新实例;所以这些项目之间不可能共享数据!!

测试它:

  • 创建一个新的 Windows Phone 应用程序(称为 AppTest
  • 添加一个 ScheduledTask 项目(称为Agent
  • AppTest 中引用项目 Agent
  • 创建一个新的 Windows Phone 库项目(称为Shared
  • AppTestAgent 中都引用了项目 Shared

然后使用这个基本的测试代码。

应用测试

private readonly string taskName = "mytest";
PeriodicTask periodicTask = null;

public MainPage()
{
    InitializeComponent();

    Vars.Apps.Add("pluto");
    Vars.Order = 5;

    StartAgent();
}

private void RemoveTask()
{
    try
    {
        ScheduledActionService.Remove(taskName);
    }
    catch (Exception)
    {
    }
}
private void StartAgent()
{
    periodicTask = ScheduledActionService.Find(taskName) as PeriodicTask;
    if (periodicTask != null)
        RemoveTask();
    periodicTask = new PeriodicTask(taskName)
    {
        Description = "test",
        ExpirationTime = DateTime.Now.AddDays(14)
    };

    try
    {
        ScheduledActionService.Add(periodicTask);
        ScheduledActionService.LaunchForTest(taskName, 
                TimeSpan.FromSeconds(10));
    }
    catch (InvalidOperationException exception)
    {
    }
    catch (SchedulerServiceException)
    {
    }
}

代理

protected override void OnInvoke(ScheduledTask task)
{
    if (Vars.Apps.Count > 0) 
        Vars.Order = 1;

    NotifyComplete();
}

共享

public static class Vars
{
    public static List<string> Apps = null;
    public static int Order;

    static Vars()
    {
        Apps = new List<string>();
        Order = -1;
    }
}

当您调试主应用程序时,您可以看到调用了静态类的静态构造函数(这是正确的),但是当调用代理时 Vars 没有“使用”但构造函数被再次调用,因此创建了一个不同的实例.
为什么?如何在主应用程序和后台代理之间共享数据?
我已经尝试将Vars 类放在代理类和命名空间中,但行为是一样的。

【问题讨论】:

    标签: c# windows-phone-7


    【解决方案1】:

    最简单的方法是使用独立存储。例如,从主应用程序:

    using (Mutex mutex = new Mutex(true, "MyData"))
    {
        mutex.WaitOne();
        try
        {
            IsolatedStorageSettings.ApplicationSettings["order"] = 5;
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
    //...
    

    在代理中:

    using (Mutex mutex = new Mutex(true, "MyData"))
    {
        mutex.WaitOne();
        try
        {
            order = (int)IsolatedStorageSettings.ApplicationSettings["order"];
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
    
    // do something with "order" here...
    

    您需要使用进程级同步和 Mutex 来防止数据损坏,因为代理和应用程序是两个独立的进程,并且可能同时使用隔离存储执行某些操作。

    【讨论】:

    • MS 建议不要为此使用 IsolatedStorageSettings,以免数据损坏。请参阅此处的“前台应用程序和后台代理之间的通信”:msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx
    • @MarkSowul 然而,他们没有详细说明数据是如何损坏的。如果“损坏”是由于缺乏同步,互斥锁将防止这种情况发生。如果不是,随机无法解释的损坏是一个巨大的问题......
    • 考虑到他们呼吁将互斥锁用于隔离存储文件,这意味着他们还担心其他事情......
    • 在我个人的痛苦经历中,我将数据存储在IsolatedStorage Settings中并在播放代理中加载数据。有时它是正确的,有时它是错误的。我花了最后两天解决这个问题。为了您自己的利益,请使用播放代理“使用标签属性进行通信”!!!
    • 对了,如果你真的想用file来实现前台和后台的通信,那么就用file和mutex吧!
    【解决方案2】:

    静态变量的值是每个加载的 App Domain 的“实例化”,这是您正在运行的进程的“子集”。因此静态变量在每个 AppDomain 中具有不同的值,因此每个正在运行的进程也具有不同的值。

    如果您必须在进程之间共享数据,则需要将其存储在某个地方(例如数据库),或者您需要在进程之间设置一些通信(例如 MSMQ 或 WCF)。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回答,听起来很有道理。但我仍然觉得这种行为很疯狂:要共享一些数据,我需要一个数据库或其他东西......让简单的事情变得困难!想象一下:我需要创建一个从电话联系人派生的集合(它应该有数百个项目长)并在主应用程序中使用它来显示数据并在后台代理中使用它来执行某些任务(例如实时磁贴更新),所以我必须保存派生的在数据库或隔离存储中列出,然后每次我想使用它时重新加载它(所以序列化和反序列化)......我无话可说......
    • 我现在不确定 - 你有 1 个应用程序还是多个?
    • 一个应用程序,这就是让我发疯的原因:后台代理不应该是主进程中的线程吗?他们不应该使用相同的App Domain吗?
    • 如果您只有一个应用程序,那么是的,您应该能够使用静态“共享”数据。如果这是最好的方法,那是另一个问题,但是是的,它应该有效。只要加载的程序集在同一个应用程序域/进程中。
    • 你试过我的代码了吗?试试(如果你有时间,哈哈)然后告诉我......我真的被困住了:(
    【解决方案3】:

    找了好久,终于找到了一个article说:

    由于我们的 EventTiles 应用程序及其 PeriodicTask 正在运行 独立的进程,它们彼此完全分离, 这意味着他们获得了自己想要的变量副本 访问,即使这些变量是在单独的项目中定义的。

    因此,使用“简单”静态变量/属性在主应用程序和周期性任务之间共享数据是不可能的;我们必须读/写数据库或隔离存储或任何我们喜欢的东西。

    我觉得这很疯狂,但这就是故事。

    【讨论】:

    • 为什么“疯狂”。当您返回或转到另一个应用程序时,您的应用程序退出;如果应用不再运行,您希望您的后台代理能够访问什么?
    • @PeterRitchie:好吧,你的应用程序退出了,但这并不意味着它“关闭”了,也许它只是暂停然后重新启动,但可以继续“生活”......这就是我所拥有的我脑海;如果这是真的,应用程序可能会被“唤醒”并通知将后台代理作为单独的线程运行,而不是作为单独的进程。我知道,这不是现实;但这就是我在接近后台代理时的想法,我绝对错了;)无论如何,如果这是模型,那么在主应用程序和代理之间共享数据真的会更容易!
    • 是的,这并不总是意味着退出;但是一旦切换到另一个应用程序,它就可以并且将退出该应用程序。这也可能在程序执行时发生,例如当电话响起时。当这种情况发生时,它被称为“墓碑”。
    【解决方案4】:

    MS 建议如下:

    前台应用程序和后台代理之间的通信

    在前台应用程序和后台代理程序之间传递信息可能具有挑战性,因为无法预测代理程序和应用程序是否会同时运行。以下是为此推荐的模式。

    1.对于定期和资源密集型代理:使用 LINQ 2 SQL 或隔离存储中的文件,该存储由互斥锁保护。对于前台应用程序写入而代理仅读取的单向通信,我们建议使用带有 Mutex 的隔离存储文件。我们建议您不要使用 IsolatedStorageSettings 在进程之间进行通信,因为数据可能会损坏。

    2.对于音频代理:将自定义数据存储在 AudioTrack 类的 Tag 属性中。对于从音频代理到前台应用程序的通知,请阅读 PlayStateChanged 事件处理程序中的 Tag 属性。要将数据从前台应用程序传递到音频代理,请在 OnPlayStateChanged(BackgroundAudioPlayer, AudioTrack, PlayState) 方法的实现中读取当前轨道的 Tag 属性。

    请看这里:http://msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx

    【讨论】:

    • 我对前台app和Playback Agent之间的通信做了很多研究,最后发现使用Tag属性是“非常正确”的方式!!!!非常感谢
    • @Peter Ritchie,抱歉,您能说得更具体一点吗?这是什么?
    • 实际上,OP 中的原始措辞似乎鼓励使用它?
    • 当然可以,例如这里来自后台音频代理代码的 sn-p .. string newTag = "new msg"; AudioTrack track = BackgroundAudioPlayer.Instance.Track; track.BeginEdit();跟踪标签=新标签; track.EndEdit();
    猜你喜欢
    • 1970-01-01
    • 2019-03-29
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 2014-11-03
    相关资源
    最近更新 更多