`
zhenzxie
  • 浏览: 66922 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Android学习之路——6.android.account包和AbstractThreadedSyncAdapter适配器

阅读更多
android.account包和AbstractThreadedSyncAdapter适配器
(一)简介:
(1)接口:
AccountManagerCallback<V>:  配合AccountManager类使用的回调接口,实现接口的类对象作为参数传给AccountManager的方法,方法在完成某项异步事务后实现回调。
AccountManagerFuture<V>: 表示调用AccountManager异步方法的结果,可以使用它的getResult()在非UI线程中进行查询异步方法结果。
OnAccountsUpdateListener:  配合AccountManager类使用的回调接口,当同步的帐号发生变化时被调用
(2)类:
AbstractAccountAuthenticator:  创建Authenticator的抽象基类
Account:  同步帐号的表示类,含有name和type两个实例域
AccountAuthenticatorActivity: 当AbstractAccountAuthenticator需要用户认证时使用的基类Activity
AccountAuthenticatorResponse:  AbstractAccountAuthenticator用来回馈AccountManager的对象(API原文:Object used to communicate responses back to the AccountManager。)
AccountManager:  集中管理用户要同步的在线帐号的类
AuthenticatorDescription:  一个可以Parcelable的,含有AccountAuthenticator类的具体信息
(3)异常:
AccountsException
AuthenticatorException
NetworkErrorException
OperationCanceledException
(4)AbstractThreadedSyncAdapter类:会开启一个线程去调用同步操作的抽象接口。

(二)介绍:
(1)Account:代表着在AccountManager中使用的值类型,这个类是实现了Parcelable接口,并且重写equals()和hashCode()方法,可以在map中使用。含有两个public final String 的实例域name和type,代表Account的名字和类型。

(2)AccountManager:
AccountManager提供了很多关于Account的操作,获得这个类的实例的方式是:AccountManager.get(Context)或者Context.getSystemService(Context.ACCOUNT_SERVICE)。但是不知道为什么在AccountManager里使用的IAccountManager这个类(或者接口)在Eclipse里打不开。

但是可以知道的是AccountManager提供的方法分两种不同类型,一种是同步的,一种是异步的。异步的方法在参数方面都是需要提供一个AccountManagerCallback接口实例和一个Handler实例,返回了一个AccountManagerFuture的接口实例。AccountManagerCallback和AccountManagerFuture都使用了泛型。应该可以认为AccountManagerFuture和AccountManagerCallback都是配合AccountManager使用的吧。

AccountManagerFuture表示的是异步调用AccountManager的结果,提供了查询和取消的方法,getResult的方法查询对AccountManager方法的调用结果,这个方法会阻塞。cancel可以取消对AccountManager方法的调用。另外提供了isCancelled()和isDone()方法来查询状态,如果已经实现了,就不能取消。对于getResult()的调用不能在主线程中进行。当对AccountManager方法的调用结束时,会调用参数中提供的AccountManagerCallback中的run方法,这个调用是通过你提供的Handler实现的(Handler参数为空时则使用默认的mMainHandler):

private void postToHandler(Handler handler, final AccountManagerCallback<Bundle> callback,
            final AccountManagerFuture<Bundle> future) {
        handler = handler == null ? mMainHandler : handler;
        handler.post(new Runnable() {
            public void run() {
                callback.run(future);
            }
        });
}

那么可以在AccountManagerCallback中的run方法中使用AccountManagerFuture的getResult()方法,从而获得结果。

另外:发现在和android.account包里的类里有使用到这样一些类(IAccountAuthenticator,IAccountAuthenticatorResponse,IAccountManager,IAccountManagerResponse)文件保存为aidl格式,无法在Eclipse中打开,可以用记事本打开。(参考资料在:android-sdk\docs\guide\developing\tools\aidl.html)

(3)AbstractAccountAuthenticator:
android.accounts.AbstractAccountAuthenticator定义处理Setting->“Accounts&sync”中Account的添加和验证等功能的基本接口,并实现了一些基本功能。AbstractAccountAuthenticator里面有个继承于IAccountAuthenticator.Stub的内部类,以用来对AbstractAccountAuthenticator的远程接口调用进行包装。我们可以通过AbstractAccountAuthenticator的getIBinder()方法,返回内部类的IBinder形式,以便对AbstractAccountAuthenticator进行远程调用(现在还不懂)。

AbstractAccountAuthenticator是一个创建AccountAuthenticators的抽象基类,一个类要成为authenticatior必须要继承这个类,实现抽象方法,并且实现一个Service,当调用Intent,action为ACTION_AUTHENTICATOR_INTENT时在这个Service的onBind(Intent)方法中返回getIBinder()的结果(API原文:provider implementations for the abstract methods and write a service that returns the result of getIBinder() in the service's onBind(android.content.Intent) when invoked with an intent with action ACTION_AUTHENTICATOR_INTENT),getIBinder() 返回其用于远程调用的IBinder。这个service要在intent filter和metadata标签中指定:

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

其中android resource必须指向如下这样的资源,所指向的xml文件应该说明该Account在“Accounts&sync”中的基本显示信息 :
<account-authenticator     xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="typeOfAuthenticator"
android:icon="@drawable/icon"
android:smallIcon="@drawable/miniIcon"
android:label="@string/label"
android:accountPreferences="@xml/account_preferences" />

上述resource 中比较重要的是account:Type属性,它必须是一个唯一表示你的Authenticator的字符串,当用户调用AccountManager时也是使用这个字符串,并且它和你的Account的Type是匹配的。还有就是android:accountPreferences属性,它指向这样的首选项:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/title_fmt" />
        <PreferenceScreen
              android:key="key1"
              android:title="@string/key1_action"
              android:summary="@string/key1_summary">
              <intent
                     android:action="key1.ACTION"
                     android:targetPackage="key1.package"
                     android:targetClass="key1.class" />
        </PreferenceScreen>
</PreferenceScreen>

当调用管理Authenticator时就会使用这个PreferenceScreens

override AbstractAccountAuthenticator那些抽象方法的标准样式如下:
①如果提供了足够多的参数,则进行处理,返回一个含有结果的Bundle。
②如果Authenticator需要更多来自用户确定请求的信息,那么创建一个Intent去启动一个Activity来提示用户相关信息,然后处理请求。这个Intent必须在Bundle中以KEY_INTENT为键返回。启动的Activity当结束时必须返回最终结果,所以Intent中也要含有以KEY_ACCOUNT_MANAGER_RESPONSE为键的AccountAuthenticatorResponse,当Activity结束时,必须调用onResult(Bundle) 或者 onError(int, String)。可以使用继承AccountAuthenticatorActivity的子类来完成所需的Activity。
③如果Authenticator不能同步处理请求然后返回结果,那么它可能选择返回null,当处理完请求时那么使用AccountManagerResponse来发送结果。
类中的方法有:
addAccount():添加一个特定类型的帐号类型
confirmCredentials():检查帐号的证书
getAuthToken():获得某个帐号的authtoken
updateCredentials():更新本地帐号的证书

(4)AccountAuthenticatorResponse:一个用来和AccountManager交流的对象(Object used to communicate responses back to the AccountManager)。主要方法是:onError()和onResult()

(5)AccountAuthenticatorActivity :一个AbstractAccountAuthenticator的帮助类的基本实现(Base class for implementing an Activity that is used to help implement an AbstractAccountAuthenticator),如果AbstractAccountAuthenticator需要一个Activity来出来处理请求,那么可以使用继承AccountAuthenticatorActivity的类。

启动Activity时,将AccountAuthenticatorResponse以KEY_ACCOUNT_AUTHENTICATOR_RESPONSE为键放到Intent中。要传递给response进行处理的结果将通过setAccountAuthenticatorResult(android.os.Bundle).来设置(API原文:The activity then sets the result that is to be handed to the response via setAccountAuthenticatorResult(android.os.Bundle).),这些结果会在Activity Finish的时候当作请求的结果而发送。如果它没有被设置或者设置为null,这引发response调用ERROR_CODE_CANCELED。AccountAuthenticatorActivity的代码实现很简单。主要是override Activity中的onCreate(Bundle)方法和finish()方法,另外又实现了一个setAccountAuthenticatorResult(android.os.Bundle)方法。

public class AccountAuthenticatorActivity extends Activity {
    private AccountAuthenticatorResponse mAccountAuthenticatorResponse = null;
    private Bundle mResultBundle = null;

    /**
     * Set the result that is to be sent as the result of the request that caused this
     * Activity to be launched. If result is null or this method is never called then
     * the request will be canceled.
     * @param result this is returned as the result of the AbstractAccountAuthenticator request
     */
    public final void setAccountAuthenticatorResult(Bundle result) {
        mResultBundle = result;
    }

    /**
     * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
     * icicle is non-zero.
     * @param icicle the save instance data of this Activity, may be null
     */
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        mAccountAuthenticatorResponse =
                getIntent().getParcelableExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);

        if (mAccountAuthenticatorResponse != null) {
            mAccountAuthenticatorResponse.onRequestContinued();
        }
    }

    /**
     * Sends the result or a Constants.ERROR_CODE_CANCELED error if a result isn't present.
     */
    public void finish() {
        if (mAccountAuthenticatorResponse != null) {
            // send the result bundle back if set, otherwise send an error.
            if (mResultBundle != null) {
                mAccountAuthenticatorResponse.onResult(mResultBundle);
            } else {
                mAccountAuthenticatorResponse.onError(AccountManager.ERROR_CODE_CANCELED,
                        "canceled");
            }
            mAccountAuthenticatorResponse = null;
        }
        super.finish();
    }
}

由上面代码很清晰的看到AccountAuthenticatorActivity的注意事项

(6)AbstractThreadedSyncAdapter:一个开启线程去调用同步操作的抽象接口,为了实现一个同步适配器就必须去继承它,并实现它的方法,另外还要实现一个action为android.content.SyncAdapter的Service,在这个Service的onBind(Intent)方法中调用并返回getSyncAdapterBinder()的结果。它主要有四个方法onPerformSync()onSyncCanceled()onSyncCanceled() getSyncAdapterBinder()。继承AbstractThreadedSysncAdapter时,主要要实现onPerformSync()方法,在这个方法中google的示例程序SampleSyncAdapter中使用了AccoutManager,ContactManager和NetworkUtilities三个类。另外实现的Service需要在AndroidManifest.xml中指定特定的intent-filter和meta-data如下:

 
<intent-filter>
      <action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />

android:resource指向这样的资源:
<sync-adapter    xmlns:android="http://schemas.android.com/apk/res/android"
           android:contentAuthority="authority"
           android:accountType="accountType"
           android:userVisible="true|false"
           android:supportsUploading="true|false"
           android:allowParallelSyncs="true|false"
           android:isAlwaysSyncable="true|false"
           android:syncAdapterSettingsAction="ACTION_OF_SETTINGS_ACTIVITY" />

(三)android.account包和AbstractThreadedSyncAdapter适配器的使用(google的实例工程SampleSyncAdapter):
(1)Authenticator,AuthenticatorActivity,AuthenticationService的实现
  Authenticator继承了AbstractAccountAuthenticator,实现了addAccount() getAuthToken() hasFeatures()三个方法。addAccount()方法中,创建了一个Intent,把AuthenticatorActivity.class传递给构造方法,应该是为了启动AuthenticatorActivity吧。然后把参数中的AccountAuthenticatorResponse对象以AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE为键放到intent中,接着把这个intent以AccountManager.KEY_INTENT为键放到一个Bundle中,并返回这个Bundle。getAuthToken()方法,先验证了password是否有效,有效的话返回一个含有Account.name,帐号类型,和authToken的Bundle,否则返回一个含有AccountManager.KEY_INTENT为键的intent的Bundle。

AuthenticatorActivity继承AccountAuthenticatorActivity,当用户填好用户和密码并点击signin按钮时,将调用handleLogin(View)。(插播一句:在xml中通过设置Button的onClick属性来设置监听,处理事件)在handleLogin(View)方法中创建了一个AsynTask的子类对象,并调用execute()方法,这个方法将回调AsynTask的子类对象中的doInBackground()从而在后台实现帐号的认证,并返回token。当doInBackground()结束后,会在UI线程中继续调用该类的onPostExecute(),接着更改本地存储的信息,再接着使用setAccountAuthenticatorResult(Bundle)方法将结果保存到父类中,然后再调用的父类的finish()方法来调用AccountAuthenticatorResponse的onResult()或者onError()方法将结果返回。而在AccountAuthenticatorResponse的onResult()或者onError()方法中又是使用IAccountAuthenticatorResponse这个的相应方法进行远程调用。所以可以知道在AuthenticatorActivity中主要是提供接受用户帐号和密码,然后认证,然后更改本地存储的信息,最后返回。

这个工程里并没有使用到AccountManagerCallback<V>  AccountManagerFuture<V> OnAccountsUpdateListener 接口,主要是没调用AccoutManager中的异步方法

AuthenticationServise:继承Service,在onCreate(Bundle)方法中创建了Authenticator实例,在onBindle(Intent)方法中返回Authenticator.getIBinder()的结果。在AndroidManifest.xml中的声明

 
<service
        android:name=".authenticator.AuthenticationService"
        android:exported="true">
        <intent-filter>
              <action
                   android:name="android.accounts.AccountAuthenticator" />
        </intent-filter>
        <meta-data
                 android:name="android.accounts.AccountAuthenticator"
                 android:resource="@xml/authenticator" />
</service>

    
(2)SyncAdapter,SyncService的实现
SyncAdapter继承AbstractThreadedSyncAdapter,复写了onPerformSync()方法,在这个方法里实现了同步
SyncService继承Service,在onCreate(Bundle)中创建SyncAdapter实例,在onBind(Intent)返回SyncAdaper.getSyncAdapterBinder()的结果。

(3)整个的使用过程:
首先这android.account包和AbstractThreadedSyncAdapter应该是某些服务商在开发自己的客户端程序使用的,通过它们来方便地实现自己的客户端上的帐号同步。创建AbstractAccountAuthenticator子类,来实现自定义认证器的功能,主要需复写的方法如上述,可以通过AccoutManager来管理帐号。实现Service的子类向系统注册Authenticator,之后只要在setting中的Accounts&sync里要对帐号添加,删除等操作都会调用AbstractAccountAuthenticator子类中的相应方法。有必要的话提供相应的Activity(继承AccountAuthenticatorActivity)来提供相应的UI界面,接受用户输入。另外创建AbstractThreadedSyncAdapter子类,复写onPerformSync()方法实现自定义的同步方法,和AbstractAccountAuthenticator相同,它也通过Service子类来向系统注册服务,每次需要更新时,都调用onPerformSync()方法。

Demo来自google的实例程序SampleSyncAdapter
6
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics