Quantcast
Channel: Recent Threads — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 204402

Getting a SyncAdapter to work

$
0
0

I've been trying to get a SyncAdapter to work. Man, what a ridiculously complicated mess. I don't even know where to begin, so I guess I'll just dump all the related code. If I put breakpoints pretty much everywhere in the code below, the following stuff actually gets called at startup:

1: StubContentProvider.OnCreate()

2: AndroidApp.InitSyncService() (called explicitly when my app starts up).

And that's it. Nothing else ever gets called.

AndroidApp.cs

public static class AndroidApp
{

    public static string ACCOUNT_TYPE = "georgesmobile.android.backgroundservice";
    public static string ACCOUNT = "mobile";
    public static string AUTHORITY = "georgesmobile.android.provider";

    public static Account SyncAccount { get; private set; }

    public static void InitSyncService(Context context)
    {
        if (SyncAccount == null)
        {
            CreateSyncAccount(context);
            ContentResolver.SetIsSyncable(AndroidApp.SyncAccount, AndroidApp.AUTHORITY, 1);
            ContentResolver.SetSyncAutomatically(AndroidApp.SyncAccount, AndroidApp.AUTHORITY, true);
            Bundle bund = new Bundle();
            ContentResolver.AddPeriodicSync(AndroidApp.SyncAccount, AndroidApp.AUTHORITY, bund, 2);
        }
    }
    private static Account CreateSyncAccount(Context context)
    {
        SyncAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
        AccountManager accountManager =  (AccountManager)context.GetSystemService(Context.AccountService);
        return SyncAccount;
    }
}

StubContentProvider.cs

[ContentProvider(new[] { "georgesmobile.android.provider" },
    Name = "georgesmobile.android.backgroundservice.StubContentProvider",
    Exported = false,
    Syncable = true)]
public class StubContentProvider : ContentProvider
{
    public override int Delete(global::Android.Net.Uri uri, string selection, string[] selectionArgs)
    {
        return 0;
    }

    public override string GetType(global::Android.Net.Uri uri)
    {
        return "";
    }

    public override global::Android.Net.Uri Insert(global::Android.Net.Uri uri, ContentValues values)
    {
        return null;
    }

    public override bool OnCreate()
    {
        return true;
    }

    public override global::Android.Database.ICursor Query(global::Android.Net.Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder)
    {
        return null;
    }

    public override int Update(global::Android.Net.Uri uri, ContentValues values, string selection, string[] selectionArgs)
    {
        return 0;
    }
}

GenericAccountService.cs

[Service(Name = "georgesmobile.android.backgroundservice.GenericAccountService")]
[IntentFilter(new string[] { "android.accounts.AccountAuthenticator" })]
[MetaData("android.accounts.AccountAuthenticator", Resource = "@xml/authenticator")]
public class GenericAccountService : Service
{
    private Authenticator _authenticator;

    public static Account GetAccount(string accountType)
    {
        return new Account(AndroidApp.ACCOUNT, AndroidApp.ACCOUNT_TYPE);
    }

    public override void OnCreate()
    {
        base.OnCreate();
        _authenticator = new Authenticator(this);
    }

    public override IBinder OnBind(Intent intent)
    {
        return _authenticator.IBinder;
    }
}

SyncAdapter.cs

public class SyncAdapter : AbstractThreadedSyncAdapter 
{

    public override void OnPerformSync(global::Android.Accounts.Account account, Bundle extras, string authority, ContentProviderClient provider, SyncResult syncResult)
    {
        BackgroundDataSync.Synchronize();
    }
}

SyncService.cs

[Service(Name = "georgesmobile.android.backgroundservice.SyncService", Exported = true)]
[MetaData("android.content.SyncAdapter", Resource = "@xml/syncadapter")]
public class SyncService : Service
{
    private static SyncAdapter _syncAdapter;
    private static object _syncLock = new object();

    public override void OnCreate()
    {
        base.OnCreate();
        lock (_syncLock)
        {
            _syncAdapter = new SyncAdapter(ApplicationContext, true);
        }
    }

    public override IBinder OnBind(Intent intent)
    {
        return _syncAdapter.SyncAdapterBinder;
    }

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        return base.OnStartCommand(intent, flags, startId);
    }
}

syncadapter.xml

<?xml version="1.0" encoding="utf-8" ?>
<sync-adapter
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:contentAuthority="georgesmobile.android.provider"
        android:accountType="georgesmobile.android.backgroundservice"
        android:userVisible="true"
        android:supportsUploading="true"
        android:allowParallelSyncs="true"
        android:isAlwaysSyncable="true"/>

authenticator.xml

<?xml version="1.0" encoding="utf-8" ?>
<account-authenticator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:icon="@drawable/georgeslogo_icon"
    android:smallIcon="@drawable/georgeslogo_icon"
    android:label="@string/AppName"        
    android:accountType="georgesmobile.android.backgroundservice"/>

relevant AndroidManifest.xml (as generated by the compiler)

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="georgesmobile.android" android:versionCode="1" android:versionName="Crackerjack">
      <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
      <uses-permission android:name="android.permission.READ_SYNC_STATS" />
      <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
      <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
      <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
      <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
      <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
      <application android:label="GeorgesMobile" android:icon="@drawable/georgeslogo_icon" android:theme="@android:style/Theme.Light" android:name="mono.android.app.Application" android:debuggable="true">
        <receiver android:name="georgesmobile.android.backgroundservice.BootupReceiver">
          <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
          </intent-filter>
        </receiver>
        <service android:name="georgesmobile.android.backgroundservice.GenericAccountService">
          <meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" />
          <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator" />
          </intent-filter>
        </service>
        <provider android:authorities="georgesmobile.android.provider" android:exported="false" android:name="georgesmobile.android.backgroundservice.StubContentProvider" android:syncable="true" />
        <service android:exported="true" android:name="georgesmobile.android.backgroundservice.SyncService">
          <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter" />
        </service>
        <activity android:icon="@drawable/georgeslogo_icon" android:label="George's Inc" android:name="georgesmobile.android.views.HomeActivity">
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
        <activity android:icon="@drawable/georgeslogo_icon" android:label="George's Login" android:name="georgesmobile.android.views.LoginActivity" />
        <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="2147483647" android:authorities="georgesmobile.android.mono.MonoRuntimeProvider.__mono_init__" />
        <receiver android:name="mono.android.Seppuku">
          <intent-filter>
            <action android:name="mono.android.intent.action.SEPPUKU" />
            <category android:name="mono.android.intent.category.SEPPUKU.georgesmobile.android" />
          </intent-filter>
        </receiver>
      </application>
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    </manifest>

I love android, but Google's documentation on how this stuff works is a pathetic joke.


Viewing all articles
Browse latest Browse all 204402

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>