java - ContentResolver.requestSync 不调用 SyncAdapter

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

因此,我遵循了有关在没有真正的 ContentProvider 和帐户的情况下创建 SyncAdapter 的教程(来自 here),但遇到了一个我无法解决的问题。

当调用 ContentResolver.requestSync() 以手动强制同步时,似乎我实现的 SyncAdapter 没有被调用。 请注意,我创建了所有 stub 类(StubAuthenticator、StubProvider、AuthenticatorService)和 SyncService,这与它们在上述教程中的创建方式完全相同。如果您需要我以任何一种方式发布代码,我将编辑这篇文章。

安卓 list .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 项目,所以我相当缺乏经验。

最佳答案

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

关于java - ContentResolver.requestSync 不调用 SyncAdapter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40405345/

相关文章:

android-studio - 移动项目后找不到 Android Studio AndroidManifest

android - 不可分配给 'android.app.activity' 扩展应用程序

java - LMAX Disruptor 如何解决典型的消息代理问题?

java - 在单独的 JSTL 循环中访问 Map 值

java - 通过android应用程序获取执行命令的输出

android - 秒获取数据,想计算时分秒

Android 通知按钮未显示

java - 使用Java和Jersey对以categoryID为键的类别进行JSON反序列化

android - 在 fragment 中,恢复一个对象,该对象包含另一个具有 Parcelable 实现的对象的列表

添加共享用户 ID 后,Android 应用无法从市场更新