【问题标题】:ContentResolver.requestSync in Sync Adapter is not working in Android同步适配器中的 ContentResolver.requestSync 在 Android 中不起作用
【发布时间】:2016-02-11 05:11:54
【问题描述】:

我正在尝试使用“StubProvider”和“StubAuthenticator”编写一个同步适配器,我遵循了官方指南,我的代码运行没有任何错误,但没有调用“onPerformSync()”,我尝试了一切但没有用.

我的完整项目可以从https://www.dropbox.com/s/48bgj3wweehaieu/MyApplication.zip?dl=0下载

这是我正在使用的类:

类 MainActivity

public class MainActivity extends FragmentActivity implements View.OnClickListener {

    // Constants
    // The authority for the sync adapter's content provider
    public static final String AUTHORITY = "com.syncadaptertest.StubProvider";
    // An account type, in the form of a domain name
    public static final String ACCOUNT_TYPE = "com.syncadaptertest";
    // The account name
    public static final String ACCOUNT = "dummyaccount";
    // Instance fields
    Account mAccount;

    private ImageButton mRefreshBtn = null;

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

        setContentView(R.layout.activity_main);

        mRefreshBtn = (ImageButton) findViewById(R.id.refreshBtn);
        mRefreshBtn.setOnClickListener(this);

        // Create the dummy account
        mAccount = CreateSyncAccount(this);

    }

    /**
     * Create a new dummy account for the sync adapter
     *
     * @param context The application context
     */
    public static Account CreateSyncAccount(Context context) {
        // Create the account type and default account
        Account newAccount = new Account(ACCOUNT, ACCOUNT_TYPE);
        // Get an instance of the Android account manager
        AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
        /*
         * Add the account and account type, no password or user data
         * If successful, return the Account object, otherwise report an error.
         */
        if (accountManager.addAccountExplicitly(newAccount, null, null)) {
            /*
             * If you don't set android:syncable="true" in
             * in your <provider> element in the manifest,
             * then call context.setIsSyncable(account, AUTHORITY, 1)
             * here.
             */
        } else {
            /*
             * The account exists or some other error occurred. Log this, report it,
             * or handle it internally.
             */
        }
        return newAccount;
    }


    @Override
    public void onClick(View v){

        onRefreshButtonClick(v);
    }



    /**
     * Respond to a button click by calling requestSync(). This is an
     * asynchronous operation.
     *
     * This method is attached to the refresh button in the layout
     * XML file
     *
     * @param v The View associated with the method call,
     * in this case a Button
     */
    public void onRefreshButtonClick(View v) {

        // Pass the settings flags by inserting them in a bundle
        Bundle settingsBundle = new Bundle();
        settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
        settingsBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
        /*
         * Request the sync for the default account, authority, and
         * manual sync settings
         */
        ContentResolver.setIsSyncable(mAccount, AUTHORITY, 1);
        ContentResolver.requestSync(mAccount, AUTHORITY, settingsBundle);

        if(ContentResolver.isSyncActive(mAccount, AUTHORITY))
        {
            Log.d("testing1","testttt");
        }
        if(ContentResolver.isSyncPending(mAccount, AUTHORITY))
        {
            Log.d("testing2","testttt2");
        }

        List<SyncInfo> myList = ContentResolver.getCurrentSyncs();

    }

}

Stub Authenticator 类

    public class Authenticator extends AbstractAccountAuthenticator {
    // Simple constructor
    public Authenticator(Context context) {
        super(context);
    }
    // Editing properties is not supported
    @Override
    public Bundle editProperties(
            AccountAuthenticatorResponse r, String s) {
        throw new UnsupportedOperationException();
    }
    // Don't add additional accounts
    @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();
    }
}

类 AuthenticatorService

    public class AuthenticatorService extends Service {

    // Instance field that stores the authenticator object
    private Authenticator mAuthenticator;
    @Override
    public void onCreate() {
        // Create a new authenticator object
        mAuthenticator = new Authenticator(this);
    }
    /*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mAuthenticator.getIBinder();
    }
}

类同步服务

    public class SyncService extends Service {
    // Storage for an instance of the sync adapter
    private static SyncAdapter sSyncAdapter = null;
    // Object to use as a thread-safe lock
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Instantiate the sync adapter object.
     */
    @Override
    public void onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = 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 sSyncAdapter.getSyncAdapterBinder();
    }
}

类 StubProvider

public class StubProvider extends ContentProvider {
    /*
     * Always return true, indicating that the
     * provider loaded correctly.
     */
    @Override
    public boolean onCreate() {
        return true;
    }
    /*
     * Return no type for MIME type
     */
    @Override
    public String getType(Uri uri) {
        return null;
    }
    /*
     * query() always returns no results
     *
     */
    @Override
    public Cursor query(
            Uri uri,
            String[] projection,
            String selection,
            String[] selectionArgs,
            String sortOrder) {
        return null;
    }
    /*
     * insert() always returns null (no URI)
     */
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }
    /*
     * delete() always returns "no rows affected" (0)
     */
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }
    /*
     * update() always returns "no rows affected" (0)
     */
    public int update(
            Uri uri,
            ContentValues values,
            String selection,
            String[] selectionArgs) {
        return 0;
    }
}

类同步适配器

public class SyncAdapter extends AbstractThreadedSyncAdapter {
    private final AccountManager mAccountManager;

    public SyncAdapter(Context context, boolean autoInitialize) {
        super(context, autoInitialize);
        mAccountManager = AccountManager.get(context);
    }

    @Override
    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
        Log.d("udinic", "onPerformSync for account[" + account.name + "]");
        try {
            // TODO Updating local tv shows

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • 您提供了很多代码,但究竟是什么不起作用?请描述您要达到的目标、预期结果和实际结果。
  • 如果onPerformSync 被调用,那么您的问题是什么?
  • 傻我,我刚刚编辑了....'onPerformSync'没有被调用。
  • 你解决了这个问题吗?我也有同样的问题

标签: java android background-process stub android-syncadapter


【解决方案1】:

你确定它不起作用吗?

请记住,Sync Adapter 运行在不在同一个进程中的绑定服务上,因此 onPerformSync() 中的 Log.d() 不会显示在应用程序主进程下的 LogCat 中,而是显示在 Sync 的进程中适配器正在使用。

尝试删除 LogCat 中的过滤器:不要选择“仅显示选定的应用程序”,而是选择“无过滤器”。

【讨论】:

  • 这真的解决了我两天前的头痛。谢谢:)
  • 同样的事情也发生在我身上。非常感谢:D
  • 哇,经过数小时的调试,这是一条黄金线索。选择“无过滤器”后,我看到了日志并意识到我没有实现动态权限处理。非常感谢!
  • 谢谢@Raphael 我已经调查了将近一个小时!
  • 感谢您以正确的解释优先指出。我在大部分地方都读过,但都忽略了。
【解决方案2】:

您是否在同步适配器的元数据 xml 中指定了您的 account_type?

你的 xml 描述符应该是这样的

<sync-adapter
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:contentAuthority="com.android.contacts"
    android:accountType="com.syncadaptertest"
    android:userVisible="true"
    android:supportsUploading="false"
    android:allowParallelSyncs="false"
    android:isAlwaysSyncable="true"/>

最重要的是它应该在你的 AndroidManifest 文件中声明

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

【讨论】:

    【解决方案3】:

    从 android 清单中删除 android:process=":sync"

    【讨论】:

      猜你喜欢
      • 2015-08-26
      • 2013-01-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多