Xamarin 与 AzureMobileServices 离线同步:初始离线加载非常慢

Xamarin Offline Sync with AzureMobileServices: Initial offline load incredibly slow

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

问题

当设备没有连接时(在各种物理和模拟设备上使用飞行模式进行测试)- 第一次访问任何离线数据时,需要 非常 很长时间 return 任何事情。如果数据存在于 SQLite DB 中,则属于这种情况。

没有抛出任何异常,也没有任何我能看到的打印到日志中的信息表明延迟可能是什么。

举个例子,20 行的 PullAsync() 在线时可能需要 5 秒,并且该数据存储在 SQLite 数据库中。将设备置于离线模式后,相同的操作最多可能需要 60 秒。这些数字是相当随意的,但延迟明显太长了。

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

预期结果

我希望因为数据已经存储在设备上,并且无法检测到互联网连接,所以它应该 return 数据几乎是即时的。

代码

同步Class

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-赶上,因为等待时间似乎在 PullAsync 上。

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

简而言之,如果您的设备处于离线状态,您不想在 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();
    }

但您还需要处理应用首次运行的情况,因此您还没有任何记录。