android - 如何与安卓联系人同步
问题描述
我正在尝试通过电话号码将我的 Firestore 用户与用户联系人同步。由于解析电话号码和匹配数据库的过程需要时间(只有 3 个用户大约需要 20 秒),并且由于应用程序也应该离线工作,即当应用程序不活动时同步,所以我似乎需要使用 SyncAdapter,但它非常复杂。
我主要(不仅)遵循了下一个教程:
https://developer.android.com/training/sync-adapters
我最初的困境是:
我还需要制作 Stub-Provider 还是可以使用 android 联系人?如果是这样,如何在 Manifest 中定义它?
联系人更改时如何触发syncAdapter?
在这段代码中,我离开了 Stub Provider 并尝试通过创建观察者来触发同步适配器,但我可以看到 toast 消息“联系人已更改!” (例如删除联系人)仅在应用程序处于活动状态时。如果我关闭应用程序,我看不到吐司。我不确定这是因为 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>
身份验证器.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"/>
同步适配器.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";
}
解决方案
推荐阅读
- html - 如何将网站图标设置为文本
- python-3.x - 如何在python中将美元金额从文本转换为数字?
- python - 需要用空格替换�
- python - argparse:确定该值是默认值还是用户输入
- reactjs - React hooks 组件在映射后未更新,但查看数据加载/刷新错误
- python - NameError:名称'plot_confusion_matrix'未定义
- python - ImportError:没有名为请求的模块,但模块已存在
- javascript - 更改画布的背景颜色
- javascript - mongoDB(在nodeJS中)聚合管道返回空数组
- javascript - 当我将鼠标悬停在文本上时,我想让图像出现。我集成了一些 JavaScript,但它仍然无法正常工作