Android 帐户同步机制

2024-01-24 02:32
文章标签 android 同步 机制 帐户

本文主要是介绍Android 帐户同步机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

装过Android版的Facebook、lastfm的同学是否对于这些应用的功能感到惊喜,它们可以定期更新朋友的最新信息,将最新近况和心情短语集成入联系人中。这些应用全部是以Android2.0后的账户和同步机制为基础的。Google的例程中给出了名为SampleSyncAdpater的例子,通过分析该例子可以学会Android中的Account验证、同步Adapter的使用。

详细例子代码可以看sdk samples中提供的源码,现在拿2.2中的版本来简要说明。

首先是 class Authenticator extends AbstractAccountAuthenticator ,该类是账户认证类,打开手机的Setting里,有Account&Sync 一项,Authenticator就是实现其中的账号功能的类。

view plain print ?
  1. // in Authenticator.java 
  2.     public Bundle addAccount(AccountAuthenticatorResponse response, 
  3.         String accountType, String authTokenType, String[] requiredFeatures, 
  4.         Bundle options) { 
  5.         final Intent intent =new Intent(mContext, AuthenticatorActivity.class); 
  6.         intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, 
  7.             authTokenType); 
  8.         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, 
  9.             response); 
  10.         final Bundle bundle = new Bundle(); 
  11.         bundle.putParcelable(AccountManager.KEY_INTENT, intent); 
  12.         return bundle; 
  13.     } 
[java] view plain copy print ?
  1. // in Authenticator.java 
  2.     public Bundle addAccount(AccountAuthenticatorResponse response, 
  3.         String accountType, String authTokenType, String[] requiredFeatures, 
  4.         Bundle options) { 
  5.         final Intent intent =new Intent(mContext, AuthenticatorActivity.class); 
  6.         intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, 
  7.             authTokenType); 
  8.         intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, 
  9.             response); 
  10.         final Bundle bundle = new Bundle(); 
  11.         bundle.putParcelable(AccountManager.KEY_INTENT, intent); 
  12.         return bundle; 
  13.     } 

其中addAccount方法用来定义需要增加账号时的操作,如调用AuthenticatorActivity来进行账号的添加认证。

在AuthenticatorActivity.java中定义了handleLogin(),此方法由login_activity.xml中的android:onClick="handleLogin"定义与ui中的okbutton的关联。

view plain print ?
  1. // in layout/login_activity.xml 
  2. <Button 
  3.             android:id="@+id/ok_button" 
  4.             android:layout_width="wrap_content" 
  5.             android:layout_height="wrap_content" 
  6.             android:layout_gravity="center_horizontal" 
  7.             android:minWidth="100dip" 
  8.             android:text="@string/login_activity_ok_button" 
  9.             android:onClick="handleLogin" /> 
[java] view plain copy print ?
  1. // in layout/login_activity.xml 
  2. <Button 
  3.             android:id="@+id/ok_button" 
  4.             android:layout_width="wrap_content" 
  5.             android:layout_height="wrap_content" 
  6.             android:layout_gravity="center_horizontal" 
  7.             android:minWidth="100dip" 
  8.             android:text="@string/login_activity_ok_button" 
  9.             android:onClick="handleLogin" /> 

handleLogin()将ui中的用户名和密码取得,并创建一个试图认证的线程,通过网络去服务端验证。

NetworkUtilities.java中的 public static boolean authenticate(String username, String password, Handler handler, final Context context)方法展示了通过网络验证的具体流程。得到服务端验证结果后,在sendResult()中通过handler.post调用来实现 onAuthenticationResult()在AuthenticatorActivity中的运行。 onAuthenticationResult()判断验证通过则结束AuthenticatorActivity,否则报出用户名密码错,让用户在 AuthenticatorActivity中再次尝试验证。

view plain print ?
  1. // AuthenticatorActivity.java中的handleLogin()方法 
  2.     /**
  3.      * Handles onClick event on the Submit button. Sends username/password to
  4.      * the server for authentication.
  5.      *
  6.      * @param view The Submit button for which this method is invoked
  7.      */ 
  8.     public void handleLogin(View view) { 
  9.         if (mRequestNewAccount) { 
  10.             mUsername = mUsernameEdit.getText().toString(); 
  11.         } 
  12.         mPassword = mPasswordEdit.getText().toString(); 
  13.         if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) { 
  14.             mMessage.setText(getMessage()); 
  15.         } else
  16.             showProgress(); 
  17.             // Start authenticating... 
  18.             mAuthThread = 
  19.                 NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler, 
  20.                     AuthenticatorActivity.this); 
  21.         } 
  22.     } 
[java] view plain copy print ?
  1. // AuthenticatorActivity.java中的handleLogin()方法 
  2.     /**
  3.      * Handles onClick event on the Submit button. Sends username/password to
  4.      * the server for authentication.
  5.      *
  6.      * @param view The Submit button for which this method is invoked
  7.      */ 
  8.     public void handleLogin(View view) { 
  9.         if (mRequestNewAccount) { 
  10.             mUsername = mUsernameEdit.getText().toString(); 
  11.         } 
  12.         mPassword = mPasswordEdit.getText().toString(); 
  13.         if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) { 
  14.             mMessage.setText(getMessage()); 
  15.         } else
  16.             showProgress(); 
  17.             // Start authenticating... 
  18.             mAuthThread = 
  19.                 NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler, 
  20.                     AuthenticatorActivity.this); 
  21.         } 
  22.     } 

view plain print ?
  1. // NetworkUtilities中的authenticate()方法通过网络访问具体来实现服务端的验证,sendResult()来使调用结果被AuthenticatorActivity的onAuthenticationResult()调用。 
  2.     /**
  3.      * Connects to the Voiper server, authenticates the provided username and
  4.      * password.
  5.      *
  6.      * @param username The user's username
  7.      * @param password The user's password
  8.      * @param handler The hander instance from the calling UI thread.
  9.      * @param context The context of the calling Activity.
  10.      * @return boolean The boolean result indicating whether the user was
  11.      *         successfully authenticated.
  12.      */ 
  13.     public staticboolean authenticate(String username, String password, 
  14.         Handler handler, final Context context) { 
  15.         final HttpResponse resp; 
  16.  
  17.         final ArrayList<NameValuePair> params =new ArrayList<NameValuePair>(); 
  18.         params.add(new BasicNameValuePair(PARAM_USERNAME, username)); 
  19.         params.add(new BasicNameValuePair(PARAM_PASSWORD, password)); 
  20.         HttpEntity entity = null
  21.         try
  22.             entity = new UrlEncodedFormEntity(params); 
  23.         } catch (final UnsupportedEncodingException e) { 
  24.             // this should never happen. 
  25.             throw new AssertionError(e); 
  26.         } 
  27.         final HttpPost post =new HttpPost(AUTH_URI); 
  28.         post.addHeader(entity.getContentType()); 
  29.         post.setEntity(entity); 
  30.         maybeCreateHttpClient(); 
  31.  
  32.         try
  33.             resp = mHttpClient.execute(post); 
  34.             if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 
  35.                 if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  36.                     Log.v(TAG, "Successful authentication"); 
  37.                 } 
  38.                 sendResult(true, handler, context); 
  39.                 return true
  40.             } else
  41.                 if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  42.                     Log.v(TAG, "Error authenticating" + resp.getStatusLine()); 
  43.                 } 
  44.                 sendResult(false, handler, context); 
  45.                 return false
  46.             } 
  47.         } catch (final IOException e) { 
  48.             if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  49.                 Log.v(TAG, "IOException when getting authtoken", e); 
  50.             } 
  51.             sendResult(false, handler, context); 
  52.             return false
  53.         } finally
  54.             if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  55.                 Log.v(TAG, "getAuthtoken completing"); 
  56.             } 
  57.         } 
  58.     } 
  59.  
  60.     /**
  61.      * Sends the authentication response from server back to the caller main UI
  62.      * thread through its handler.
  63.      *
  64.      * @param result The boolean holding authentication result
  65.      * @param handler The main UI thread's handler instance.
  66.      * @param context The caller Activity's context.
  67.      */ 
  68.     private staticvoid sendResult(final Boolean result,final Handler handler, 
  69.         final Context context) { 
  70.         if (handler == null || context ==null) { 
  71.             return
  72.         } 
  73.         handler.post(new Runnable() { 
  74.             public void run() { 
  75.                 ((AuthenticatorActivity) context).onAuthenticationResult(result); 
  76.             } 
  77.         }); 
  78.     } 
[java] view plain copy print ?
  1. // NetworkUtilities中的authenticate()方法通过网络访问具体来实现服务端的验证,sendResult()来使调用结果被AuthenticatorActivity的onAuthenticationResult()调用。 
  2.     /**
  3.      * Connects to the Voiper server, authenticates the provided username and
  4.      * password.
  5.      *
  6.      * @param username The user's username
  7.      * @param password The user's password
  8.      * @param handler The hander instance from the calling UI thread.
  9.      * @param context The context of the calling Activity.
  10.      * @return boolean The boolean result indicating whether the user was
  11.      *         successfully authenticated.
  12.      */ 
  13.     public staticboolean authenticate(String username, String password, 
  14.         Handler handler, final Context context) { 
  15.         final HttpResponse resp; 
  16.  
  17.         final ArrayList<NameValuePair> params =new ArrayList<NameValuePair>(); 
  18.         params.add(new BasicNameValuePair(PARAM_USERNAME, username)); 
  19.         params.add(new BasicNameValuePair(PARAM_PASSWORD, password)); 
  20.         HttpEntity entity = null
  21.         try
  22.             entity = new UrlEncodedFormEntity(params); 
  23.         } catch (final UnsupportedEncodingException e) { 
  24.             // this should never happen. 
  25.             throw new AssertionError(e); 
  26.         } 
  27.         final HttpPost post =new HttpPost(AUTH_URI); 
  28.         post.addHeader(entity.getContentType()); 
  29.         post.setEntity(entity); 
  30.         maybeCreateHttpClient(); 
  31.  
  32.         try
  33.             resp = mHttpClient.execute(post); 
  34.             if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 
  35.                 if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  36.                     Log.v(TAG, "Successful authentication"); 
  37.                 } 
  38.                 sendResult(true, handler, context); 
  39.                 return true
  40.             } else
  41.                 if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  42.                     Log.v(TAG, "Error authenticating" + resp.getStatusLine()); 
  43.                 } 
  44.                 sendResult(false, handler, context); 
  45.                 return false
  46.             } 
  47.         } catch (final IOException e) { 
  48.             if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  49.                 Log.v(TAG, "IOException when getting authtoken", e); 
  50.             } 
  51.             sendResult(false, handler, context); 
  52.             return false
  53.         } finally
  54.             if (Log.isLoggable(TAG, Log.VERBOSE)) { 
  55.                 Log.v(TAG, "getAuthtoken completing"); 
  56.             } 
  57.         } 
  58.     } 
  59.  
  60.     /**
  61.      * Sends the authentication response from server back to the caller main UI
  62.      * thread through its handler.
  63.      *
  64.      * @param result The boolean holding authentication result
  65.      * @param handler The main UI thread's handler instance.
  66.      * @param context The caller Activity's context.
  67.      */ 
  68.     private staticvoid sendResult(final Boolean result,final Handler handler, 
  69.         final Context context) { 
  70.         if (handler == null || context ==null) { 
  71.             return
  72.         } 
  73.         handler.post(new Runnable() { 
  74.             public void run() { 
  75.                 ((AuthenticatorActivity) context).onAuthenticationResult(result); 
  76.             } 
  77.         }); 
  78.     } 

view plain print ?
  1. // AuthenticatorActivity.java中的onAuthenticationResult,来根据验证结果来选择结束认证或重新尝试。 
  2.     /**
  3.      * Called when the authentication process completes (see attemptLogin()).
  4.      */ 
  5.     public void onAuthenticationResult(boolean result) { 
  6.         Log.i(TAG, "onAuthenticationResult(" + result +")"); 
  7.         // Hide the progress dialog 
  8.         hideProgress(); 
  9.         if (result) { 
  10.             if (!mConfirmCredentials) { 
  11.                 finishLogin(); 
  12.             } else
  13.                 finishConfirmCredentials(true); 
  14.             } 
  15.         } else
  16.             Log.e(TAG, "onAuthenticationResult: failed to authenticate"); 
  17.             if (mRequestNewAccount) { 
  18.                 // "Please enter a valid username/password. 
  19.                 mMessage 
  20.                     .setText(getText(R.string.login_activity_loginfail_text_both)); 
  21.             } else
  22.                 // "Please enter a valid password." (Used when the 
  23.                 // account is already in the database but the password 
  24.                 // doesn't work.) 
  25.                 mMessage 
  26.                     .setText(getText(R.string.login_activity_loginfail_text_pwonly)); 
  27.             } 
  28.         } 
  29.     } 
[java] view plain copy print ?
  1. // AuthenticatorActivity.java中的onAuthenticationResult,来根据验证结果来选择结束认证或重新尝试。 
  2.     /**
  3.      * Called when the authentication process completes (see attemptLogin()).
  4.      */ 
  5.     public void onAuthenticationResult(boolean result) { 
  6.         Log.i(TAG, "onAuthenticationResult(" + result +")"); 
  7.         // Hide the progress dialog 
  8.         hideProgress(); 
  9.         if (result) { 
  10.             if (!mConfirmCredentials) { 
  11.                 finishLogin(); 
  12.             } else
  13.                 finishConfirmCredentials(true); 
  14.             } 
  15.         } else
  16.             Log.e(TAG, "onAuthenticationResult: failed to authenticate"); 
  17.             if (mRequestNewAccount) { 
  18.                 // "Please enter a valid username/password. 
  19.                 mMessage 
  20.                     .setText(getText(R.string.login_activity_loginfail_text_both)); 
  21.             } else
  22.                 // "Please enter a valid password." (Used when the 
  23.                 // account is already in the database but the password 
  24.                 // doesn't work.) 
  25.                 mMessage 
  26.                     .setText(getText(R.string.login_activity_loginfail_text_pwonly)); 
  27.             } 
  28.         } 
  29.     } 

Account的验证完毕后,就生成了账号,可以开始使用同步功能了。同步的主要逻辑在public class SyncAdapter extends AbstractThreadedSyncAdapter中实现。

view plain print ?
  1. // SyncAdapter.java中的OnPerformSync方法,主要的同步逻辑 
  2.     @Override 
  3.     public void onPerformSync(Account account, Bundle extras, String authority, 
  4.         ContentProviderClient provider, SyncResult syncResult) { 
  5.         List<User> users; 
  6.         List<Status> statuses; 
  7.         String authtoken = null
  8.          try
  9.              // use the account manager to request the credentials 
  10.              authtoken = 
  11.                 mAccountManager.blockingGetAuthToken(account, 
  12.                     Constants.AUTHTOKEN_TYPE, true/* notifyAuthFailure */); 
  13.              // fetch updates from the sample service over the cloud 
  14.              users = 
  15.                 NetworkUtilities.fetchFriendUpdates(account, authtoken, 
  16.                     mLastUpdated); 
  17.             // update the last synced date. 
  18.             mLastUpdated = new Date(); 
  19.             // update platform contacts. 
  20.             Log.d(TAG, "Calling contactManager's sync contacts"); 
  21.             ContactManager.syncContacts(mContext, account.name, users); 
  22.             // fetch and update status messages for all the synced users. 
  23.             statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken); 
  24.             ContactManager.insertStatuses(mContext, account.name, statuses); 
  25.         } catch (final AuthenticatorException e) { 
  26.             syncResult.stats.numParseExceptions++; 
  27.             Log.e(TAG, "AuthenticatorException", e); 
  28.         } catch (final OperationCanceledException e) { 
  29.             Log.e(TAG, "OperationCanceledExcetpion", e); 
  30.         } catch (final IOException e) { 
  31.             Log.e(TAG, "IOException", e); 
  32.             syncResult.stats.numIoExceptions++; 
  33.         } catch (final AuthenticationException e) { 
  34.             mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, 
  35.                 authtoken); 
  36.             syncResult.stats.numAuthExceptions++; 
  37.             Log.e(TAG, "AuthenticationException", e); 
  38.         } catch (final ParseException e) { 
  39.             syncResult.stats.numParseExceptions++; 
  40.             Log.e(TAG, "ParseException", e); 
  41.         } catch (final JSONException e) { 
  42.             syncResult.stats.numParseExceptions++; 
  43.             Log.e(TAG, "JSONException", e); 
  44.         } 
  45.     } 
[java] view plain copy print ?
  1. // SyncAdapter.java中的OnPerformSync方法,主要的同步逻辑 
  2.     @Override 
  3.     public void onPerformSync(Account account, Bundle extras, String authority, 
  4.         ContentProviderClient provider, SyncResult syncResult) { 
  5.         List<User> users; 
  6.         List<Status> statuses; 
  7.         String authtoken = null
  8.          try
  9.              // use the account manager to request the credentials 
  10.              authtoken = 
  11.                 mAccountManager.blockingGetAuthToken(account, 
  12.                     Constants.AUTHTOKEN_TYPE, true/* notifyAuthFailure */); 
  13.              // fetch updates from the sample service over the cloud 
  14.              users = 
  15.                 NetworkUtilities.fetchFriendUpdates(account, authtoken, 
  16.                     mLastUpdated); 
  17.             // update the last synced date. 
  18.             mLastUpdated = new Date(); 
  19.             // update platform contacts. 
  20.             Log.d(TAG, "Calling contactManager's sync contacts"); 
  21.             ContactManager.syncContacts(mContext, account.name, users); 
  22.             // fetch and update status messages for all the synced users. 
  23.             statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken); 
  24.             ContactManager.insertStatuses(mContext, account.name, statuses); 
  25.         } catch (final AuthenticatorException e) { 
  26.             syncResult.stats.numParseExceptions++; 
  27.             Log.e(TAG, "AuthenticatorException", e); 
  28.         } catch (final OperationCanceledException e) { 
  29.             Log.e(TAG, "OperationCanceledExcetpion", e); 
  30.         } catch (final IOException e) { 
  31.             Log.e(TAG, "IOException", e); 
  32.             syncResult.stats.numIoExceptions++; 
  33.         } catch (final AuthenticationException e) { 
  34.             mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, 
  35.                 authtoken); 
  36.             syncResult.stats.numAuthExceptions++; 
  37.             Log.e(TAG, "AuthenticationException", e); 
  38.         } catch (final ParseException e) { 
  39.             syncResult.stats.numParseExceptions++; 
  40.             Log.e(TAG, "ParseException", e); 
  41.         } catch (final JSONException e) { 
  42.             syncResult.stats.numParseExceptions++; 
  43.             Log.e(TAG, "JSONException", e); 
  44.         } 
  45.     } 

onPerformSync中的执行流程中,使用NetworkUtilities中的fetchFriendUpdates和 fetchFriendStatuses来访问服务端的联系人更新,并使用了例程中自己封装的ContactManager来读取、更新联系人信息。

那Account和SyncAdapter及其Service和xml定义之间是如何关联的呢? AndroidManifest.xml中定义了AccountAuthenticator,SyncAdapter及对应的Service和xml定义的关联。

view plain print ?
  1. <application 
  2.     android:icon="@drawable/icon" 
  3.     android:label="@string/label"
  4.     <!-- The authenticator service --> 
  5.     <service 
  6.         android:name=".authenticator.AuthenticationService" 
  7.         android:exported="true"
  8.         <intent-filter> 
  9.             <action 
  10.                 android:name="android.accounts.AccountAuthenticator" /> 
  11.         </intent-filter> 
  12.         <meta-data 
  13.             android:name="android.accounts.AccountAuthenticator" 
  14.             android:resource="@xml/authenticator" /> 
  15.     </service> 
  16.     <service 
  17.         android:name=".syncadapter.SyncService" 
  18.         android:exported="true"
  19.         <intent-filter> 
  20.             <action 
  21.                 android:name="android.content.SyncAdapter" /> 
  22.         </intent-filter> 
  23.         <meta-data 
  24.             android:name="android.content.SyncAdapter" 
  25.             android:resource="@xml/syncadapter" /> 
  26.         <meta-data 
  27.             android:name="android.provider.CONTACTS_STRUCTURE" 
  28.             android:resource="@xml/contacts" /> 
  29.     </service> 
  30.     <activity 
  31.         android:name=".authenticator.AuthenticatorActivity" 
  32.         android:label="@string/ui_activity_title" 
  33.         android:theme="@android:style/Theme.Dialog" 
  34.         android:excludeFromRecents="true" 
  35.         > 
  36.         <!-- 
  37.             No intent-filter here! This activity is only ever launched by 
  38.             someone who explicitly knows the class name 
  39.         --> 
  40.     </activity> 
  41. </application> 
[java] view plain copy print ?
  1. <application 
  2.     android:icon="@drawable/icon" 
  3.     android:label="@string/label"
  4.     <!-- The authenticator service --> 
  5.     <service 
  6.         android:name=".authenticator.AuthenticationService" 
  7.         android:exported="true"
  8.         <intent-filter> 
  9.             <action 
  10.                 android:name="android.accounts.AccountAuthenticator" /> 
  11.         </intent-filter> 
  12.         <meta-data 
  13.             android:name="android.accounts.AccountAuthenticator" 
  14.             android:resource="@xml/authenticator" /> 
  15.     </service> 
  16.     <service 
  17.         android:name=".syncadapter.SyncService" 
  18.         android:exported="true"
  19.         <intent-filter> 
  20.             <action 
  21.                 android:name="android.content.SyncAdapter" /> 
  22.         </intent-filter> 
  23.         <meta-data 
  24.             android:name="android.content.SyncAdapter" 
  25.             android:resource="@xml/syncadapter" /> 
  26.         <meta-data 
  27.             android:name="android.provider.CONTACTS_STRUCTURE" 
  28.             android:resource="@xml/contacts" /> 
  29.     </service> 
  30.     <activity 
  31.         android:name=".authenticator.AuthenticatorActivity" 
  32.         android:label="@string/ui_activity_title" 
  33.         android:theme="@android:style/Theme.Dialog" 
  34.         android:excludeFromRecents="true" 
  35.         > 
  36.         <!-- 
  37.             No intent-filter here! This activity is only ever launched by 
  38.             someone who explicitly knows the class name 
  39.         --> 
  40.     </activity> 
  41. </application> 

更详细的代码细节和执行流程,可以去把SDK中的SampleSyncAdapter代码运行起来体会一下,不过要实现整个流程,必须搭建联系人的服务器端,例程中在目录samplesyncadapter_server中也提供了简单的server端python代码,需要搭建在google app engine上。搭建过程遇到一些问题,由于对python不熟我弄了几天才解决好搭建成功,其中遇到的一个model moudle找不到的问题需要你在model中新建一个__init__.py的空文件,来说明是一个python模块,如果你也遇到此问题,希望对你有帮助。


以上是从别人那里看到的一篇不错的文章,以下是自己在源码开发过程中的一些总结:

在AccountManagerService.java和RegisteredServicesCache.java的generateServicesMap()方法里会解析所有的功能清单里配置的有关帐户同步的 service。如果没有解析到会将当前加入的帐户信息删除。


帐户信息保存在:data/system/account.db
                                data/system/sync
                                data/system/registered-services下面

涉到的service包括:

<service
            android:name=".myservices.ContactsSyncAdapterService"
            android:exported="true">
            <intent-filter>
                <action android:name="android.content.SyncAdapter" />
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter"
                       android:resource="@xml/syncadapter_contacts" />
          </service>
       
          <service
            android:name=".myservices.CalendarSyncAdapterService"
            android:exported="true">
            <intent-filter>
                <action android:name="android.content.SyncAdapter" />
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter"
                       android:resource="@xml/syncadapter_calendar" />
          </service>  
       
          <service
            android:name=".myservices.SyncManager"
            android:enabled="true"
            >
          </service>  
       
          <service
            android:name=".service.EasAuthenticatorService"
            android:exported="true"
            android:enabled="true"
            >
            <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=".myservices.EasAuthenticatorServiceAlternate"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>
            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator_alternate"
                />
          </service>

这篇关于Android 帐户同步机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/638276

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Java如何通过反射机制获取数据类对象的属性及方法

《Java如何通过反射机制获取数据类对象的属性及方法》文章介绍了如何使用Java反射机制获取类对象的所有属性及其对应的get、set方法,以及如何通过反射机制实现类对象的实例化,感兴趣的朋友跟随小编一... 目录一、通过反射机制获取类对象的所有属性以及相应的get、set方法1.遍历类对象的所有属性2.获取