I'm running a sync adapter that periodically check if there are new data available at the remote server. If there is a new data I want to create a notification about it. It seems that the whole mechanism works fine but not EVERY time. Sometimes I don't get a notification. And sometimes it works flawless. I can't figure out why. Maybe I miss some crucial knowledge about a syncadapter implementation in android?
My SyncAdapter onPerformSync function:
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient contentProviderClient, SyncResult syncResult) {
SyncResult result = new SyncResult();
try {
Log.w("APPP", "HERE SYNC!!!!!");
isNewPrivateMessageWasReceivedInCurrentUpdate=false;
receiveMessages(contentProviderClient);
deleteMessages(contentProviderClient);
} catch (RemoteException | IOException e) {
syncResult.hasHardError();
}
finally {
if(isNewMessageWasReceivedInCurrentUpdate) {
MainActivity ma = (MainActivity) MainActivity.GetContext();
ma.startNotification("New messages", "", true);
}
}
isNewMessageWasReceivedInCurrentUpdate variable gets updated it receiveMessages function.
startNotification function
public void startNotification(String contentTitle, String contentText, Boolean isChat) {
notification = new NotificationCompat.Builder(MainActivity.this);
notification.setAutoCancel(true);
notification.setContentTitle(contentTitle);
notification.setContentText(contentText);
notification.setTicker("New Messages!");
notification.setSmallIcon(R.drawable.ic_launcher);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notification.setSound(alarmSound);
stackBuilder = TaskStackBuilder.create(MainActivity.this);
stackBuilder.addParentStack(MainActivity.class);
resultIntent = new Intent(MainActivity.this, MainActivity.class);
if (isChat) {
resultIntent.putExtra(TAB_TO_SHOW, TAB_CHATS);
}
stackBuilder.addNextIntent(resultIntent);
pIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setContentIntent(pIntent);
manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (isChat) {
manager.notify(NotificationID.MESSAGES.ordinal(), notification.build());
}
}
SyncAdapter initialization in MainActivity
newAccountPrivate = new Account("Private", getResources().getString(R.string.account_name));
ContentResolver.setSyncAutomatically(
newAccountPrivate, MainActivity.PROVIDER_NAME, true);
ContentResolver.addPeriodicSync(newAccountPrivate, MainActivity.PROVIDER_NAME, Bundle.EMPTY, 300);//SYNC_INTERVAL);
ContentResolver.setIsSyncable(newAccountPrivate, MainActivity.PROVIDER_NAME, 1);
ContentResolver.setMasterSyncAutomatically(true);
AccountManager accountManagerPrivate = AccountManager.get(this);
accountManagerPrivate.addAccountExplicitly(newAccountPrivate, null, null);
Manifest file
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<service android:name=".AuthenticatorService"
android:exported="true"
android:process=":auth">>
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<provider
android:name=".DataContentProvider"
android:authorities="authority.provider"
android:exported="false"
android:multiprocess="true"
android:syncable="true"/>
<service
android:name=".SyncService"
android:exported="true">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
SyncService
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class SyncService extends Service {
private static SyncAdapter syncAdapter = null;
// Object to use as a thread-safe lock
private static final Object syncAdapterLock = new Object();
public SyncService() {
super();
}
@Override
public void onCreate() {
super.onCreate();
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (syncAdapterLock) {
if (syncAdapter == null) {
syncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*/
@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/
return syncAdapter.getSyncAdapterBinder();
}
}
SyncAdapter.xml
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="authority.provider"
android:accountType="@string/account_name"
android:userVisible="true"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true"/>
Thank you!