【问题标题】:Xamarin Offline Sync with AzureMobileServices: Initial offline load incredibly slowXamarin 与 AzureMobileServices 脱机同步:初始脱机加载速度非常慢
【发布时间】:2018-11-09 22:14:12
【问题描述】:

我成功地使用 Azure 移动服务和 Xamarin Forms 在 Azure 托管的 SQL DB 上执行 CRUD 操作。离线同步部分将数据存储在手机上的 SQLite 数据库中。在让它像我们现在一样顺利运行的过程中遇到了一些障碍,但这仍然是最后一个障碍。

问题

当设备没有连接时(在各种物理和模拟设备上使用飞行模式进行测试)- 第一次访问任何离线数据时,需要非常长时间退回任何东西。无论数据是否存在于 SQLite DB 中都是这种情况。

没有抛出异常,或者我可以看到的任何内容都打印到日志中,表明延迟可能是什么。

给出一个想法,20 行上的PullAsync() 在线时可能需要 5 秒,并且该数据存储到 SQLite DB。将设备置于离线模式后,相同的操作可能需要长达 60 秒。这些数字相当随意,但延迟明显太长了。

此外,这种长时间加载仅在第一次调用任何离线同步方法时发生。在那之后,每一种方法都几乎是即时的,正如我所期望的那样——但为什么不是第一次呢?

预期结果

我希望由于数据已经存储在设备上,并且无法检测到互联网连接,它应该几乎立即返回数据。

代码

同步类

GetPolicies()方法是延迟发生的地方。 这是其中一个组件的示例。其他所有组件的格式相同,但数据不同。

    IMobileServiceSyncTable<policy_procedure> policyTable = SyncController.policyTable;

    public async Task<List<policy_procedure>> GetPolicies(string companyId)
    {
        //SemaphoreSlim
        await SyncController.dbOperation.WaitAsync();
        try
        {
            await SyncController.Initialize();
            await policyTable.PullAsync("policy_procedure", policyTable.Where(p => p.fk_company_id == companyId).Where(p=> p.signature!=null || p.signature!=""));
            return await policyTable.ToListAsync();
        }
        catch (Exception ex)
        {
            //For some reason, when this method is called and the device is offline, it will fall into this catch block. 
            //I assume this is standard for offline sync, as it's trying to do a pull with no connection, causing it to fail. 
            //Through using breakpoints, the delay occurs even before it reaches this catch statement.
            Console.WriteLine(ex);
            return await policyTable.ToListAsync();
        }
        finally
        {
            SyncController.dbOperation.Release();
        }
    }
    
    

同步控制器

    public static SemaphoreSlim dbOperation = new SemaphoreSlim(1, 1);
    public static MobileServiceClient client;
    public static MobileServiceSQLiteStore store;
    public static async Task Initialize()
    {
        try
        {
            //This line is not standard for Offline Sync.
            //The plugin returns true or false for the devices current connectivity. 
            //It's my attempt to see if there is a connection, to eliminate the load time.
            //This does immediately take it back to the try statement in GetPolicies
            if (!CrossConnectivity.Current.IsConnected)
                return;
            if (client ? .SyncContext ? .IsInitialized ? ? false)
                return;
            client = new MobileServiceClient(AppSettings.azureUrl);
            var path = "local.db"; //Normally uses company ID, 
            path = Path.Combine(MobileServiceClient.DefaultDatabasePath, path);
            store = new MobileServiceSQLiteStore(path);
            /************************/
            #
            region Table Definitions in local SQLite DB
            //Define all the tables in the sqlite db
            ..
            store.DefineTable < policy_procedure > ();
                ..#endregion
            await client.SyncContext.InitializeAsync(store);
            /************/
            #
            region Offline Sync Tables
                ..
            policyTable = client.GetSyncTable < policy_procedure > ();
                ..#endregion
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex)
        }
    }

我的尝试

好吧,我不太确定是什么导致了这种情况,所以我的大部分尝试都是在这个等待时间发生之前强制异常,这样它就可以脱离GetPolicies try-catch,因为等待时间似乎在 PullAsync 上。

我最近的尝试在上面的代码 (SyncController) 中进行了注释,我使用 James Montemagno 的 Connectivity Plugin 来检测电话网络连接。 (我已经单独测试过了,它可以正常工作,没有延迟。)

【问题讨论】:

    标签: sqlite asynchronous xamarin.forms azure-mobile-services offline-caching


    【解决方案1】:

    简而言之,如果您的设备处于离线状态,您不想在 GetPolicies 方法中调用 PullAsync。例如,你可以这样做

        try
        {
            await SyncController.Initialize();
            if (CrossConnectivity.Current.IsConnected)
            {
                await policyTable.PullAsync("policy_procedure", policyTable.Where(p => p.fk_company_id == companyId).Where(p=> p.signature!=null || p.signature!=""));
            }
            return await policyTable.ToListAsync();
        }
    

    但您还需要处理这是应用程序第一次运行并且您还没有任何记录的情况。

    【讨论】:

    • 非常感谢 Eric,我能够解决我的问题。我没有在每个同步类中实现它,而是在 Intitialize 中的 try/catch 的 finally 部分进行了检查。异常在同步类本身中成功捕获。非常感谢!
    • 嗨@Eric Hedstrom - 作为对此的跟进,还有什么其他可能导致.ToListAsync() 非常缓慢的原因吗?在上述解决方案已经到位的情况下,我们偶尔会看到 first 加载到任何列表会花费不合理的时间。此加载完成后,任何后续加载(仍处于脱机状态)到任何其他列表都会立即发生。
    猜你喜欢
    • 2018-12-12
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 2018-06-22
    相关资源
    最近更新 更多