Enable offline sync for your Xamarin.Android mobile app
Overview
This tutorial introduces the offline sync feature of Azure Mobile Apps for Xamarin.Android. Offline sync allows end users to interact with a mobile app--viewing, adding, or modifying data--even when there is no network connection. Changes are stored in a local database. Once the device is back online, these changes are synced with the remote service.
In this tutorial, you update the client project from the tutorial Create a Xamarin Android app to support the offline features of Azure Mobile Apps. If you do not use the downloaded quick start server project, you must add the data access extension packages to your project. For more information about server extension packages, see Work with the .NET backend server SDK for Azure Mobile Apps.
To learn more about the offline sync feature, see the topic Offline Data Sync in Azure Mobile Apps.
Update the client app to support offline features
Azure Mobile App offline features allow you to interact with a local database when you are in an offline scenario. To use these features in your app, you initialize a SyncContext to a local store. Then reference your table through the IMobileServiceSyncTable interface. SQLite is used as the local store on the device.
- In Visual Studio, open the NuGet package manager in the project that you completed in the Create a Xamarin Android app tutorial. Search for and install the Microsoft.Azure.Mobile.Client.SQLiteStore NuGet package.
- Open the ToDoActivity.cs file and uncomment the
#define OFFLINE_SYNC_ENABLED
definition. - In Visual Studio, press the F5 key to rebuild and run the client app. The app works the same as it did before you enabled offline sync. However, the local database is now populated with data that can be used in an offline scenario.
Update the app to disconnect from the backend
In this section, you break the connection to your Mobile App backend to simulate an offline situation. When you add data items, your exception handler tells you that the app is in offline mode. In this state, new items added in the local store and are synced to the mobile app backend when a push is executed in a connected state.
Edit ToDoActivity.cs in the shared project. Change the applicationURL to point to an invalid URL:
const string applicationURL = @"https://your-service.azurewebsites.fail";
You can also demonstrate offline behavior by disabling wifi and cellular networks on the device or using airplane mode.
Press F5 to build and run the app. Notice your sync failed on refresh when the app launched.
Enter new items and notice that push fails with a [CancelledByNetworkError] status each time you click Save. However, the new todo items exist in the local store until they can be pushed to the mobile app backend. In a production app, if you suppress these exceptions the client app behaves as if it's still connected to the mobile app backend.
Close the app and restart it to verify that the new items you created are persisted to the local store.
(Optional) In Visual Studio, open Server Explorer. Navigate to your database in Azure->SQL Databases. Right-click your database and select Open in SQL Server Object Explorer. Now you can browse to your SQL database table and its contents. Verify that the data in the backend database has not changed.
(Optional) Use a REST tool such as Fiddler or Postman to query your mobile backend, using a GET query in the form
https://<your-mobile-app-backend-name>.azurewebsites.net/tables/TodoItem
.
Update the app to reconnect your Mobile App backend
In this section, reconnect the app to the mobile app backend. When you first run the application, the OnCreate
event handler calls
OnRefreshItemsSelected
. This method calls SyncAsync
to sync your local store with the backend database.
Open ToDoActivity.cs in the shared project, and revert your change of the applicationURL property.
Press the F5 key to rebuild and run the app. The app syncs your local changes with the Azure Mobile App backend using push and pull operations when the
OnRefreshItemsSelected
method executes.(Optional) View the updated data using either SQL Server Object Explorer or a REST tool like Fiddler. Notice the data has been synchronized between the Azure Mobile App backend database and the local store.
In the app, click the check box beside a few items to complete them in the local store.
CheckItem
callsSyncAsync
to sync each completed item with the Mobile App backend.SyncAsync
calls both push and pull. Whenever you execute a pull against a table that the client has made changes to, a push is always executed automatically. This ensures all tables in the local store along with relationships remain consistent. This behavior may result in an unexpected push. For more information on this behavior, see Offline Data Sync in Azure Mobile Apps.
Review the client sync code
The Xamarin client project that you downloaded when you completed the tutorial Create a Xamarin Android app already contains code supporting offline synchronization using a local SQLite database. Here is a brief overview of what is already included in the tutorial code. For a conceptual overview of the feature, see Offline Data Sync in Azure Mobile Apps.
Before any table operations can be performed, the local store must be initialized. The local store database is initialized when
ToDoActivity.OnCreate()
executesToDoActivity.InitLocalStoreAsync()
. This method creates a local SQLite database using theMobileServiceSQLiteStore
class provided by the Azure Mobile Apps client SDK.The
DefineTable
method creates a table in the local store that matches the fields in the provided type,ToDoItem
in this case. The type doesn't have to include all the columns that are in the remote database. It is possible to store just a subset of columns.// ToDoActivity.cs private async Task InitLocalStoreAsync() { // new code to initialize the SQLite store string path = Path.Combine(System.Environment .GetFolderPath(System.Environment.SpecialFolder.Personal), localDbFilename); if (!File.Exists(path)) { File.Create(path).Dispose(); } var store = new MobileServiceSQLiteStore(path); store.DefineTable<ToDoItem>(); // Uses the default conflict handler, which fails on conflict // To use a different conflict handler, pass a parameter to InitializeAsync. // For more details, see https://go.microsoft.com/fwlink/?LinkId=521416. await client.SyncContext.InitializeAsync(store); }
The
toDoTable
member ofToDoActivity
is of theIMobileServiceSyncTable
type instead ofIMobileServiceTable
. The IMobileServiceSyncTable directs all create, read, update, and delete (CRUD) table operations to the local store database.You decide when changes are pushed to the Azure Mobile App backend by calling
IMobileServiceSyncContext.PushAsync()
. The sync context helps preserve table relationships by tracking and pushing changes in all tables a client app has modified whenPushAsync
is called.The provided code calls
ToDoActivity.SyncAsync()
to sync whenever the todoitem list is refreshed or a todoitem is added or completed. The code syncs after every local change.In the provided code, all records in the remote
TodoItem
table are queried, but it is also possible to filter records by passing a query id and query toPushAsync
. For more information, see the section Incremental Sync in Offline Data Sync in Azure Mobile Apps.// ToDoActivity.cs private async Task SyncAsync() { try { await client.SyncContext.PushAsync(); await toDoTable.PullAsync("allTodoItems", toDoTable.CreateQuery()); // query ID is used for incremental sync } catch (Java.Net.MalformedURLException) { CreateAndShowDialog (new Exception ("There was an error creating the Mobile Service. Verify the URL"), "Error"); } catch (Exception e) { CreateAndShowDialog (e, "Error"); } }