如何与Android通讯录同步

时间:2019-04-14 06:57:59

标签: android

我正在尝试通过电话号码将我的Firestore用户与用户“联系人”同步。 由于解析电话号码并与db匹配的过程需要时间(仅3个用户大约需要20秒),并且由于该应用程序也应该脱机工作,即在应用程序不活动时进行同步,因此似乎我需要使用SyncAdapter,但这非常复杂。

我主要(不仅是)关注了下一个教程:

https://developer.android.com/training/sync-adapters

我最初的困境是:

  1. 我是否仍需要创建Stub-Provider或可以使用android Contacts?如果是这样,如何在清单中定义它?

  2. 联系人更改时如何触发syncAdapter?

在这段代码中,我离开了Stub Provider,并试图通过创建观察者来触发syncadapter,但是我可以看到吐司消息“ Contacts Changed!”。 (例如删除联系人)仅在应用程序处于活动状态时。如果我关闭了该应用程序,则看不到吐司。我不确定这是因为Toast没有上下文,还是因为观察者没有激活。

    public class MainActivity extends AppCompatActivity {

    private static final String TAG = "[MainActivity]: ";

    private Context mContext = this;

    Account mAccount;

    public class TableObserver extends ContentObserver {

        public TableObserver(Handler handler) {
            super( handler );
        }

        @Override
        public void onChange(boolean selfChange) {

            runOnUiThread( new Runnable() {
                @Override
                public void run() {
                    Toast.makeText( mContext, "Contacts Changed!-1", Toast.LENGTH_SHORT ).show();

                }
            } );
            onChange(selfChange, null);
        }

        @Override
        public void onChange(boolean selfChange, Uri changeUri) {

            runOnUiThread( new Runnable() {
                @Override
                public void run() {
                    Toast.makeText( mContext, "Contacts Changed!-2", Toast.LENGTH_SHORT ).show();
                }
            } );

            ContentResolver.requestSync(mAccount, Constants.AUTHORITY, null);
        }

        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main );

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

        getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true,
                new TableObserver(null));

    }

    public static Account CreateSyncAccount(Context context) {

        Account newAccount = new Account(
                Constants.ACCOUNT, Constants.ACCOUNT_TYPE);

        AccountManager accountManager =
                (AccountManager) context.getSystemService(
                        ACCOUNT_SERVICE);

        if (accountManager.addAccountExplicitly(newAccount, null, null)) {

            Toast.makeText( context, "i think account created successful", Toast.LENGTH_SHORT ).show();

            return newAccount;
        } else {

            Toast.makeText( context, "some error in account creation", Toast.LENGTH_SHORT ).show();

            //TODO: handle errors
            return newAccount;
        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ranslist.android.ranslist">

    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET"/>


    <application
....

        <provider
            android:name=".sync.StubProvider"
            android:authorities="com.ranslist.android.ranslist.provider"
            android:exported="false"
            android:syncable="true"/>

        <service android:name=".sync.AuthenticationService" >
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>

            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator" />
        </service>

        <service
            android:name=".sync.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/syncadapter" />
        </service>

...

        <service
            android:name="com.google.android.gms.measurement.AppMeasurementJobService"
            android:enabled="true"
            android:exported="false"
            android:permission="android.permission.BIND_JOB_SERVICE" />


....
    </application>

</manifest>

authenticator.xml

<account-authenticator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="example.com"
    android:icon="@drawable/ic_launcher_foreground"
    android:smallIcon="@drawable/ic_launcher_foreground"
    android:label="@string/app_name"/>

syncadapter.xml

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

常量

public class Constants {

    public static final String AUTHORITY = "com.example.android.datasync.provider";

    public static final String ACCOUNT_TYPE = "example.com";

    public static final String ACCOUNT = "dummyaccount";
}

0 个答案:

没有答案