ContentResolver.requestSync不会调用SyncAdapter

时间:2016-11-03 15:22:28

标签: java android android-manifest android-contentprovider android-syncadapter

所以我按照教程创建了一个没有真正的ContentProvider和一个帐户的SyncAdapter(来自here),但遇到了一个我无法解决的问题。

当调用ContentResolver.requestSync()手动强制同步时,似乎我实现的SyncAdapter不会被调用。 请注意,我在所提到的教程中创建了所有存根类(StubAuthenticator,StubProvider,AuthenticatorService)和SyncService。如果您需要我以任何方式发布代码,我将编辑此帖子。

Android Manifest.xml

<application


    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
    <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.GET_ACCOUNTS"/>

    ...        

    <service
        android:name=".datasync.SyncService"
        android:exported="true"
        android:process=":sync">
        <intent-filter>
            <action android:name="android.content.SyncAdapter"/>
        </intent-filter>
        <meta-data
            android:name="android.content.SyncAdapter"
            android:resource="@xml/sync_adapter"/>
    </service>

    <service
        android:name=".datasync.AuthenticatorService">
        <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=".datasync.StubProvider"
        android:authorities="myexample.com.provider"
        android:enabled="true"
        android:exported="false"
        android:label="DataSyncContentProvider"
        android:syncable="true"/>

</application>

sync_adapter.xml

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

authenticator.xml

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="myexample.com.account"
    android:label="MyExampleApp"/>

DataSyncAdapter.java

public class DataSyncAdapter extends AbstractThreadedSyncAdapter{

    public DataSyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
                          SyncResult syncResult) {
        Log.d(MainActivity.TAG, "onPerformSync: Called");

        //do sync stuff here
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity{
    /**
     * Tag for own application.
     */
    public static final String TAG = "com.myexample";

    @Override
    protected final void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //create UI here...

        Bundle syncExtras = new Bundle();
        //add additional sync stuff (internal)
        DataSyncUtil.createSyncRequest(this, syncExtras);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
        grantResults) {
        switch (requestCode) {
            case PERMISSIONS_GET_ACCOUNTS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Bundle syncExtras = new Bundle();

                    //add additional sync stuff (internal)

                    DataSyncUtil.createSyncRequest(this, syncExtras);
                } else {
                    //TODO handle permission denied
                }
                return;
        }
    }
}

DataSyncUtil.java

public class DataSyncUtil {

    public static void createSyncRequest(Activity activity, Bundle extras) {
        Log.d(MainActivity.TAG, "createSyncRequest: Called");
        String authority = "myexample.com.provider";
        Account dummy = getDummySyncAccount(activity);
        if (dummy != null) {
            if (ContentResolver.isSyncPending(dummy, authority) ||
                ContentResolver.isSyncActive(dummy, authority)) {
                Log.i(MainActivity.TAG, "SyncPending, canceling");
                ContentResolver.cancelSync(dummy, authority);
            }
            extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
            extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

            ContentResolver.requestSync(dummy, authority, extras);
        }
    }

    public static Account getDummySyncAccount(Activity activity) {
        String auth_type = "myexample.com.account;
        Account dummy = null;
        AccountManager accountManager = (AccountManager) activity.getSystemService(ACCOUNT_SERVICE);

        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.GET_ACCOUNTS) !=
            PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.GET_ACCOUNTS},
                    MainActivity.PERMISSIONS_GET_ACCOUNTS);
        } else {
            Account[] existing = accountManager.getAccountsByType(auth_type);
            if (existing != null && existing.length > 0) {
                //TODO handle more than one account
                Log.d(MainActivity.TAG, "getDummySyncAccount: Account already exists and is getting returned");
                dummy = existing[0];
            } else {
                Log.d(MainActivity.TAG, "getDummySyncAccount: Account has to be created");
                // Create the account type and default account
                dummy = new Account(ACCOUNT, auth_type);
                // Get an instance of the Android account manager
                /*
                 * Add the account and account type, no password or user data
                 * If successful, return the Account object, otherwise report an error.
                 */
                if (accountManager.addAccountExplicitly(dummy, null, null)) {
                    ContentResolver.setIsSyncable(dummy, "myexample.com.content", 1);
                    ContentResolver.setSyncAutomatically(dummy, "myexample.com.content", true);
                } else {
                /*
                 * The account exists or some other error occurred.Log this, report it,
                 * or handle it internally.
                 */

                }
            }
        }
        Log.d(MainActivity.TAG, "getDummySyncAccount: "+dummy.name);
        return dummy;
    }

}

代码执行得非常好,直到DataSyncUtil类中的ContentResolver.requestSync(),但DataSyncAdapter永远不会被调用。

我很感激任何帮助:)

仅供参考:这是我的第一个大型Android项目,所以我很缺乏经验。

1 个答案:

答案 0 :(得分:2)

看来我犯了一个菜鸟错误。确实调用了onPerformSync()。但我在我的android监视器集中有过滤器“仅显示选定的应用程序”,因此后台同步服务中的Log.d没有显示。 This回答帮助了我。