账户更新功能

账户更新

一.SyncService

账号更新功能需要一个服务来提供,让SyncService继承自Service来实现账号更新功能,和AuthenticatorService一样需要在onBind方法中返回一个IBinder,这里需要借助于SyncAdapter,关于SyncAdapter稍后在做描述,通过syncAdapter.getSyncAdapterBinder()方法就可以获取到IBinder对象。

    @Override

    public IBinder onBind(Intent intent) {

        return syncAdapter.getSyncAdapterBinder();

    }

  

需要注意的是实例化syncAdapter的过程要保证线程安全,以免同步框架会将多次同步响应添加到队列中。清单文件中配置如下:

   <service

        android:name=".accountrefresh.SyncService"

        android:exported="true">

        <intent-filter>

            <action android:name="android.content.SyncAdapter" />

        </intent-filter>

        <meta-data

            android:name="android.content.SyncAdapter"

            android:resource="@xml/syncadapter" />

        <meta-data

            android:name="android.provider.CONTACTS_STRUCTURE"

            android:resource="@xml/contacts" />

    </service>

为了便于数据的传输和更新,在这里使用provider。一个适配器只能同步一个Authority,若想使一个账户同步多个Authority,可以向系统注册多个绑定同一账户的sync-adapter,syncadapter配置如下:

    <?xml version="1.0" encoding="utf-8"?>

    <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"

        android:accountType="com.account.accountmanagerdemo"

        android:allowParallelSyncs="false"

        android:contentAuthority="com.android.contacts"

        android:isAlwaysSyncable="true"

        android:supportsUploading="false"

        android:userVisible="false" >

    </sync-adapter>

    1.accountType账号类型,需要与前面在代码段中的ACCOUNT_TYPE 常量还有authenticator的元数据文件中定义的保持一致。

    2.allowParallelSyncs是否支持上传到云端,否则仅支持下载。

    3.userVisible是否支持在设置中可见。

    4.设置是否允许SyncAdapter多实例同时运行。

    5.指定同步框架是否可以在任意时间运行你的SyncAdapter。

二.AccountContentProvider

1.账户更新数据的存储获取可以与ContentProvider框架协作,来存储更新数据,不仅是方便使用SyncAdapter,而且它也具有更好的安全性。这里可以使用一个虚拟的ContentProvider,可以全部返回null或者0。

public class AccountContentProvider extends ContentProvider {

        @Override

        public boolean onCreate() {

            return false;

        }

        @Nullable

        @Override

        public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {

            return null;

        }

        @Nullable

        @Override

        public String getType(@NonNull Uri uri) {

            return null;

        }

        @Nullable

        @Override

        public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {

            return null;

        }

        @Override

        public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {

            return 0;

        }

        @Override

        public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {

            return 0;

        }

    }

    2.清单文件配置

<provide

        android:name=".accountrefresh.AccountContentProvider"

        android:authorities="com.account.accountmanagerdemo.accountrefresh.provider"

        android:exported="false"

        android:syncable="true">

      (1)authorities用来唯一指定一个ContentProvider的URI authority。这个值最好设置为“包名 + .provider”。

      (2)指定实现ContentProvider的完整类名。

      (3)设置外部应用是否可以访问。因为我们的Provider并不需要别的应用访问,所以设置为”false”。这个值并不影响同步框架的访问。android:exported="false"。

      (4)设置是否可同步。如果设置为true 就不需要在代码中再调用setIsSyncable() 。这个值决定了同步框架可以与Provider传输数据,但是也仅在你明确调用的时候才传输。android:syncable="true"。

三.AbstractThreadedSyncAdapter

AbstractThreadedSyncAdapter是一个抽象类,用于账户的同步操作,它是对 Account的内容进行同步操作的适配器。当他收到同步请求时,产生一个线程来进行Account指定内容的同步处理。同步框架用的ContentPrivder框架协作,同时需要SyncAdapter做支持,否则崩溃这里,定义一个类SyncAdapter,让他继承自AbstractThreadedSyncAdapter。

    1.原理

    SyncAdapter不会自动做数据传输,它只是封装你的代码,以便框架可以在后台调用,而不需要你的应用介入。同步框架准备要同步应用数据的时候,它会调用SyncAdapter中实现的onPerformSync()方法。应该通过定期任务或是根据一些事件的结果来运行SyncAdapter。比如,隔一段时间或在每天某个特殊的时间运行,或是在本地数据变化后运行。

    2.调用时机

     (1)服务端数据变化时

        服务端数据变化时,根据服务端发送的消息运行。这样可以避免轮询服务器影响性能和功耗。

     (2)本地数据变化时

        本地数据变化后同步可以将本地变化的数据发送到服务端,适合用来确保服务端数据最新。如果数据真的是用ContentProvider保存的,那这方式是很容易实现的(在ContentProvider中使用ContentResolver的 notifyChange(android.net.Uri ,android.database.ContentObserver, boolean)方法);如果是伪造的ContentProvider,那可能要麻烦一些。

     (3)系统发送网络消息时

        当系统发出保持TCP/IP连接开启的网络消息时发起,这个网络消息是网络框架的一部分。这是自动同步的一种方式,可以考虑和基于时间间隔同步结合起来使用。

     (4)固定时间间隔

        自定义一个固定的时间间隔,或者是每天的某个时间点发起。

     (5)即时发起

        由用户手动操作发起。但是,为了有更好的体验,最好还是以自动同步为主,这样可以降低电池和网络资源的消耗。

      3.更新

      更新调用ContentResolver的requestSync(Account account, String authority, Bundle extras)方法进行数据更新。强烈建议使用自动刷新账号以及SyncAdapter中其他刷新方式,为了测试期间,这里举例手动刷新,在AuthenticatorActivity界面调用手动调用刷新:

private void refreshAccount() {

           Bundle bundle = new Bundle();

           bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);

           bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);

           ContentResolver.requestSync(CreateSyncAccount(), ConstantsGlobal.AUTHORITY, bundle);

       }

        private static final String oldAccountName = "中央电视台";//此数据一般是账号变更或者服务器返回新账号

        public Account CreateSyncAccount() {

            // 创建账户类型和默认账户名称

            Account newAccount = new Account(oldAccountName, ConstantsGlobal.ACCOUNT_TYPE);

            /*

             * 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.

                 */

               Log.e("AuthenticatorActivity", "账户更新成功");

                Toast.makeText(this,"更新成功,请重新点击查看账户列表",Toast.LENGTH_SHORT).show();

            } else {

                /*

                 * The account exists or some other error occurred. Log this, report it,

                 * or handle it internally.

                 */

                Log.e("AuthenticatorActivity", "账户更新失败,或者此账户已经存在");

                Toast.makeText(this,"更新成功,数据没有变化,请查看列表",Toast.LENGTH_SHORT).show();

            }

            return newAccount;

        }

    4.onPerformSync方法

  @Override

    public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {

    }

    4.1 参数含义:

    (1)与本次触发事件关联的Account对象,如果你的服务器不需要账号,直接无视就可以。

    (2)包含一些标志位的Bundle对象。

    (3)系统中ContentProvider的authority,一般是你自己应用中的ContentProvider对应的authority。

    (4)authority对应的ContentProviderClient,它是ContentProvider的一个轻量接口,具有与ContentResolver相同的功能。如果是用ContentProvider保存的数据,你可以用这个对象连接到ContentProvider,否则无视就好。

    (5)SyncResult对象,可以用来将同步的结果传给同步框架。

    4.2 操作步骤

     (1)连接服务器

     虽然同步开始时你可以认为网络是通畅的,但是同步框架并不会自动帮你连接服务器

     (2)下载上传数据

     SyncAdapter不会自动做数据传输。如果你要从服务端取数据存到本地,那你必须提供请求、下载、插入数据的代码。同样,如果需要上传数据,也要读数据、发送数据请求。除此之外,还需要处理数据传输中发生的网络错误。

     (3)处理数据冲突

     SyncAdapter不会自动处理服务端和本地的数据冲突。而且,也不会检测本地和服务端的数据哪一个更新。你必须自己提供算法处理这种场景。

     (4)清理

     在传输结束后关闭与服务器的链接,清理临时文件和缓存。

     注意: 同步框架自动将onPerformSync()放在后台线程,因此不需要自己设置后台运。

    需要添加权限如下:

    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>

    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>

    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>

    <uses-permission android:name="android.permission.USE_CREDENTIALS"/>

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时代我西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值