My app includes a sync adapter; it has been working fine for years, but recently I've received a very strange crash report:
Samsung Galaxy S6 Edge+ (zenlte), 4096MB RAM, Android 7.0
java.lang.ClassCastException:
1. at com.myappid.android.ScormApplication.getApplication (ScormApplication.java:34)
2. at com.myappid.android.sync.SyncAdapter.onPerformSync (SyncAdapter.java:98)
3. at android.content.AbstractThreadedSyncAdapter$SyncThread.run (AbstractThreadedSyncAdapter.java:272)
ScormApplication.java:
public class ScormApplication extends Application {
//...
public static ScormApplication getApplication(Context context) {
if (context instanceof ScormApplication) {
return (ScormApplication) context;
}
return (ScormApplication) context.getApplicationContext(); // this is a line 34
}
//...
}
SyncAdapter.java:
public class SyncAdapter extends AbstractThreadedSyncAdapter {
//...
@Override
public void onPerformSync(Account account,
Bundle extras,
String authority,
ContentProviderClient provider,
SyncResult syncResult) {
// sync code here...
ScormApplication.getApplication(getContext()).sendOttoEvent(ottoEvent); // this is a line 98
}
}
Thus, it means that the returned object from the method getApplicationContext
called on SyncAdapter's context is not an instance of my application class. But how can it be possible?
Here is a bit more of my code:
AndroidManifest.xml (no separate process is declared) :
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<application ...>
...
<service
android:name="com.myappid.android.sync.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>
...
SyncService.java:
public class SyncService extends Service {
private static SyncAdapter sSyncAdapter = null;
private static final Object sSyncAdapterLock = new Object();
@Override
public void onCreate() {
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
}
}
}
@Override
public IBinder onBind(Intent intent) {
return sSyncAdapter.getSyncAdapterBinder();
}
}
@xml/syncadapter:
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/content_authority"
android:accountType="@string/account_type"
android:userVisible="true"
android:supportsUploading="true"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true" />