Android学习之路——6.android.account包和AbstractThreadedSyncAdapter适配器
看到这个包的原因是看到AccountAuthenticatorActivity类,然后就找到这个包了,学习了不少东西。
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这个类对我来说太过于复杂了,以后再研究吧。
但是可以知道的是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); } });}<action android:name="android.accounts.AccountAuthenticator" /> </intent-filter><meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" /><intent-filter>
<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" />
<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:target/> </PreferenceScreen></PreferenceScreen>
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(); }}<intent-filter> <action android:name="android.content.SyncAdapter" /></intent-filter><meta-dataandroid:name="android.content.SyncAdapter"android:resource="@xml/syncadapter" />
<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" />
<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>