Reputation: 537
I am creating an Android App that is providing a button to the user to refresh the database so that the local data and the data on the server remains in sync.
I have created the Account Authenticator, Content Provider and have bind them through a service. The ContentResolver.requestSync() isnt triggering onPerformSync().
Here is what I have got for the code:
public void refreshButton(View view) {
Log.v("aye", "reached here");
Bundle settings = new Bundle();
settings.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL,true);
settings.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
Account dummyAccount = createDummyAccount(this);
ContentResolver.requestSync(dummyAccount,MyContract.AUTHORITY,settings);
}
private Account createDummyAccount(Context context) {
Account dummyAccount = new Account("dummyaccount","com.example.sid.fetchdata");
AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
try {
accountManager.addAccountExplicitly(dummyAccount, null, null);
} catch (Exception e) {
e.printStackTrace();
}
ContentResolver.setSyncAutomatically(dummyAccount, MyContract.AUTHORITY, true);
ContentResolver.setIsSyncable(dummyAccount,MyContract.AUTHORITY,1);
return dummyAccount;
}
I am using a dummy account and have created a stub account authenticator according to the Android Developers Guide.
Here's how my SyncAdapter class looks like:
public class MySyncAdapter extends AbstractThreadedSyncAdapter {
private ContentResolver contentResolver;
public MySyncAdapter(Context context,boolean autoInitialize) {
super(context,autoInitialize);
contentResolver = context.getContentResolver();
}
public MySyncAdapter(Context context,boolean autoInitialize,boolean allowParallelSyncs) {
super(context,autoInitialize,allowParallelSyncs);
contentResolver = context.getContentResolver();
}
@Override
public void onPerformSync(Account account,Bundle extras,String authority,ContentProviderClient providerClient,SyncResult syncResult) {
// android.os.Debug.waitForDebugger();
// Log.e("first","Sync Started");
GetData getData = new GetData(getContext());
ContentValues[] questionsContentValues = getData.getAndParseDataContentValues();
try {
Log.d("inside","Inside");
int deletedRows = providerClient.delete(MyContract.CONTENT_URI, null, null);
// int addedRows = contentResolver.bulkInsert(MyContract.CONTENT_URI,questionsContentValues);
// providerClient.insert(MyContract.CONTENT_URI,questionsContentValues[0]);
// Log.v("third1","" + addedRows);
contentResolver.notifyChange(MyContract.CONTENT_URI,null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here's how my AndroidManfiest.xml is structured:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.sid.fetchdata">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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.READ_SYNC_STATS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service
android:name=".RetrieveService"
android:exported="false" />
<activity
android:name=".FetchActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ListActivity"
android:label="@string/title_activity_list"
android:parentActivityName=".FetchActivity"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.sid.fetchdata.FetchActivity" />
</activity>
<activity
android:name=".SwipeActivity"
android:label="@string/title_activity_swipe"
android:parentActivityName=".ListActivity"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.sid.fetchdata.ListActivity" />
</activity>
<provider
android:name=".MyContentProvider"
android:syncable="true"
android:exported="true"
android:authorities="com.example.sid.fetchdata.provider" />
<service
android:name=".MyService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator" />
</service>
<service
android:name=".SyncService"
android:process=":sync"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/my_sync_adapter" />
</service>
</application>
The corresponding classes are, MyService is bound to the MyStubAuthenticator and SyncService is bound to SyncAdapter.
The xml files for MyStubAuthenticaor:
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
xmlns:android="http://schemas.android.com/apk/res/android"
android:icon="@mipmap/ic_launcher"
android:smallIcon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:accountType="com.example.sid.fetchdata" />
The xml file for SyncAdapter is:
<?xml version="1.0" encoding="utf-8"?>
<sync-adapter
xmlns:android="http://schemas.android.com/apk/res/android"
android:isAlwaysSyncable="true"
android:allowParallelSyncs="false"
android:supportsUploading="false"
android:userVisible="true"
android:accountType="com.example.sid.fetchdata"
android:contentAuthority="com.example.sid.fetchdata.provider" />
The contract class for the Provider is as follows:
public class MyContract {
public static final String AUTHORITY = "com.example.sid.fetchdata.provider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + QuestionDataBaseHelper.TABLE_QUESTIONS);
public static final int QUESTIONS = 1;
public static final int QUESTIONS_ID = 2;
public static final String SINGLE_RECORD_MIME_TYPE = "vnd.android.cursor.item/vnd.com.example.sid.fetchdata.provider.questions";
public static final String MULTIPLE_RECORDS_MIME_TYPE = "vnd.android.cursor.dir/vnd.com.example.sid.fetchdata.provider.questions";
}
I have checked that the ContentProvider is working by using it on a separate thread. The account is showing up in the Accounts section in the Settings option of the phone. The Syncing is stuck at Syncing Now...
Upvotes: 2
Views: 1498
Reputation: 537
Finally fixed the problem. The problem was with the onPerformSync() function. The function was being triggered by requestSync() but
contentResolver.notifyChange(MyContract.CONTENT_URI,null);
was the problem. The function as given in the Docs tells that the last argument syncToNetwork determines if the changes are synced to the network. Since I wasn't passing it false, an infinite loop was triggered and hence the sync was taking infinite time to complete.
So the correct call would be,
contentResolver.notifyChange(MyContract.CONTENT_URI,null,false);
Upvotes: 2