我已经尝试了两天,没有休息,但是我的同步适配器在请求定期同步后将永远不会触发。请求的同步间隔为30秒,但是即使在logcat配置中更改为NO-FILTER后,也不会调用onperform。请查看下面的代码,请帮忙。我一直在打着头,毫无希望。尽管该帐户已在android设置帐户下成功创建,并且可以通过刷新成功手动进行同步。
public class ServiceSyncAdapter extends AbstractThreadedSyncAdapter {
//TODO change this constant SYNC_INTERVAL to change the sync frequency
public static final int SYNC_INTERVAL = 30; //60 * 180; // 60 seconds (1 minute) * 180 = 3 hours
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/2;
private static final int MOVIE_NOTIFICATION_ID = 3004;
public ServiceSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.i(AppUtils.LOG_TAG, "onPerformSync");
//TODO get some data from the internet, api calls, etc.
//TODO save the data to database, sqlite, couchbase, etc
//notifyDataDownloaded();
}
/**
* Send the notification message to the status bar
*/
/*private void notifyDataDownloaded() {
Context context = getContext();
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(android.support.v7.appcompat.R.drawable.notification_template_icon_bg)
.setContentTitle("Sync Adapter")
.setContentText("New Data Available!");
// Opening the app when the user clicks on the notification.
Intent resultIntent = new Intent(context, MainActivity.class);
// The stack builder object will contain an artificial back stack for the started Activity.
// This ensures that navigating backward from the Activity leads out of your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(MOVIE_NOTIFICATION_ID, mBuilder.build()); // MOVIE_NOTIFICATION_ID allows you to update the notification later on.
}*/
/**
* Helper method to schedule the sync adapter periodic execution
*/
public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
Account account = getSyncAccount(context);
String authority = context.getString(R.string.content_authority);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// we can enable inexact timers in our periodic sync
SyncRequest request = new SyncRequest.Builder()
.syncPeriodic(syncInterval, flexTime)
.setSyncAdapter(account, authority)
.setExtras(new Bundle()).build();
ContentResolver.requestSync(request);
} else {
ContentResolver.addPeriodicSync(account, authority, new Bundle(), syncInterval);
}
//ContentResolver.addPeriodicSync(account, authority, new Bundle(), syncInterval);
}
/**
* Helper method to have the sync adapter sync immediately
* @param context The context used to access the account service
*/
public static void syncImmediately(Context context) {
Log.i(AppUtils.LOG_TAG, "syncImmediately");
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(getSyncAccount(context), context.getString(R.string.content_authority), bundle);
}
/**
* Helper method to get the fake account to be used with SyncAdapter, or make a new one
* if the fake account doesn't exist yet. If we make a new account, we call the
* onAccountCreated method so we can initialize things.
*
* @param context The context used to access the account service
* @return a fake account.
*/
public static Account getSyncAccount(Context context) {
AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); // Get an instance of the Android account manager
Account newAccount = new Account(context.getString(R.string.app_name), context.getString(R.string.sync_account_type)); // Create the account type and default account
// If the password doesn't exist, the account doesn't exist
if (accountManager.getPassword(newAccount) == null) {
if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
Log.e(AppUtils.LOG_TAG, "getSyncAccount Failed to create new account.");
return null;
}
onAccountCreated(newAccount, context);
}
return newAccount;
}
private static void onAccountCreated(Account newAccount, Context context) {
Log.i(AppUtils.LOG_TAG, "onAccountCreated");
//ContentResolver.setMasterSyncAutomatically(true);
//ContentResolver.setIsSyncable(newAccount, context.getString(R.string.content_authority), 1);
ServiceSyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);
ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.content_authority), true);
syncImmediately(context);
}
public static void initializeSyncAdapter(Context context) {
Log.d(AppUtils.LOG_TAG, "initializeSyncAdapter");
getSyncAccount(context);
}
}
public class ServiceSync extends Service {
private static final Object sSyncAdapterLock = new Object();
private static ServiceSyncAdapter myServiceSyncAdapter = null;
@Override
public void onCreate() {
super.onCreate();
Log.d(AppUtils.LOG_TAG, "onCreate ServiceSync");
synchronized (sSyncAdapterLock) {
if (myServiceSyncAdapter == null) {
myServiceSyncAdapter = new ServiceSyncAdapter(getApplicationContext(), true);
}
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d(AppUtils.LOG_TAG, "onBind ServiceSync");
return myServiceSyncAdapter.getSyncAdapterBinder();
}
}
public class AuthenticatorService extends Service {
private AccountAuthenticator mAuthenticator;
@Override
public void onCreate() {
Log.d(AppUtils.LOG_TAG, "onCreate");
// Create a new authenticator object
mAuthenticator = new AccountAuthenticator(this);
}
/*
* When the system binds to this Service to make the RPC call
* return the authenticator's IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
Log.d(AppUtils.LOG_TAG, "onBind");
return mAuthenticator.getIBinder();
}
}
public class AccountAuthenticator extends AbstractAccountAuthenticator {
public AccountAuthenticator(Context context) {
super(context);
}
// No properties to edit.
@Override
public Bundle editProperties(
AccountAuthenticatorResponse r, String s) {
throw new UnsupportedOperationException();
}
// Because we're not actually adding an account to the device, just return null.
@Override
public Bundle addAccount(
AccountAuthenticatorResponse r,
String s,
String s2,
String[] strings,
Bundle bundle) throws NetworkErrorException {
return null;
}
// Ignore attempts to confirm credentials
@Override
public Bundle confirmCredentials(
AccountAuthenticatorResponse r,
Account account,
Bundle bundle) throws NetworkErrorException {
return null;
}
// Getting an authentication token is not supported
@Override
public Bundle getAuthToken(
AccountAuthenticatorResponse r,
Account account,
String s,
Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
// Getting a label for the auth token is not supported
@Override
public String getAuthTokenLabel(String s) {
throw new UnsupportedOperationException();
}
// Updating user credentials is not supported
@Override
public Bundle updateCredentials(
AccountAuthenticatorResponse r,
Account account,
String s, Bundle bundle) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
// Checking features for the account is not supported
@Override
public Bundle hasFeatures(
AccountAuthenticatorResponse r,
Account account, String[] strings) throws NetworkErrorException {
throw new UnsupportedOperationException();
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.international.sonet.eac5">
<uses-permission android:name="android.permission.INTERNET" />
<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"/>
<application
android:name="android.support.multidex.MultiDexApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".HomeActivity"
android:label="@string/title_activity_news"
android:theme="@style/AppTheme.NoActionBar" />
<provider
android:authorities="@string/content_authority"
android:name="com.international.sonet.services.StubProvider"
android:exported="false"
android:syncable="true" />
<!-- SyncAdapter's dummy authentication service -->
<service android:name="com.international.sonet.services.AuthenticatorService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<!-- The SyncAdapter service -->
<service
android:name="com.international.sonet.services.ServiceSync"
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>
</application>
</manifest>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/sync_account_type"
android:icon="@android:drawable/ic_dialog_info"
android:label="@string/app_name"
android:smallIcon="@android:drawable/ic_dialog_info" />
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/content_authority"
android:accountType="@string/sync_account_type"
android:userVisible="true"
android:supportsUploading="false"
android:allowParallelSyncs="false"
android:isAlwaysSyncable="true" />
我正在从家庭活动oncreate()初始化适配器,
ServiceSyncAdapter.initializeSyncAdapter(getApplicationContext());
ProviderStub扩展了ContentProvider