一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

構(gòu)建自己的Android賬戶與內(nèi)容同步機(jī)制,例程SampleSyncAdapter的分析

 windli筆記 2011-08-08

裝過Android版的Facebook、lastfm的同學(xué)是否對于這些應(yīng)用的功能感到驚喜,它們可以定期更新朋友的最新信息,將最新近況和心情短語集成入聯(lián)系人中。這些應(yīng)用全部是以Android2.0后的賬戶和同步機(jī)制為基礎(chǔ)的。Google的例程中給出了名為SampleSyncAdpater的例子,通過分析該例子可以學(xué)會Android中的Account驗(yàn)證、同步Adapter的使用。

 

詳細(xì)例子代碼可以看sdk samples中提供的源碼,現(xiàn)在拿2.2中的版本來簡要說明。

 

 

首先是 class Authenticator extends AbstractAccountAuthenticator ,該類是賬戶認(rèn)證類,打開手機(jī)的Setting里,有Account&Sync 一項(xiàng),Authenticator就是實(shí)現(xiàn)其中的賬號功能的類。

  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方法用來定義需要增加賬號時的操作,如調(diào)用AuthenticatorActivity來進(jìn)行賬號的添加認(rèn)證。

在AuthenticatorActivity.java中定義了handleLogin(),此方法由login_activity.xml中的android:onClick="handleLogin"定義與ui中的okbutton的關(guān)聯(lián)。

  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中的用戶名和密碼取得,并創(chuàng)建一個試圖認(rèn)證的線程,通過網(wǎng)絡(luò)去服務(wù)端驗(yàn)證。

NetworkUtilities.java中的 public static boolean authenticate(String username, String password, Handler handler, final Context context)方法展示了通過網(wǎng)絡(luò)驗(yàn)證的具體流程。得到服務(wù)端驗(yàn)證結(jié)果后,在sendResult()中通過handler.post調(diào)用來實(shí)現(xiàn)onAuthenticationResult()在AuthenticatorActivity中的運(yùn)行。onAuthenticationResult()判斷驗(yàn)證通過則結(jié)束AuthenticatorActivity,否則報(bào)出用戶名密碼錯,讓用戶在AuthenticatorActivity中再次嘗試驗(yàn)證。

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

 

 

  1. // NetworkUtilities中的authenticate()方法通過網(wǎng)絡(luò)訪問具體來實(shí)現(xiàn)服務(wù)端的驗(yàn)證,sendResult()來使調(diào)用結(jié)果被AuthenticatorActivity的onAuthenticationResult()調(diào)用。   
  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 static boolean 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 static void 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.     }  

 

 

  1. // AuthenticatorActivity.java中的onAuthenticationResult,來根據(jù)驗(yàn)證結(jié)果來選擇結(jié)束認(rèn)證或重新嘗試。   
  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的驗(yàn)證完畢后,就生成了賬號,可以開始使用同步功能了。同步的主要邏輯在public class SyncAdapter extends AbstractThreadedSyncAdapter中實(shí)現(xiàn)。

  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中的執(zhí)行流程中,使用NetworkUtilities中的fetchFriendUpdates和fetchFriendStatuses來訪問服務(wù)端的聯(lián)系人更新,并使用了例程中自己封裝的ContactManager來讀取、更新聯(lián)系人信息。

 

那Account和SyncAdapter及其Service和xml定義之間是如何關(guān)聯(lián)的呢? AndroidManifest.xml中定義了AccountAuthenticator,SyncAdapter及對應(yīng)的Service和xml定義的關(guān)聯(lián)。

  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>  

 

 

更詳細(xì)的代碼細(xì)節(jié)和執(zhí)行流程,可以去把SDK中的SampleSyncAdapter代碼運(yùn)行起來體會一下,不過要實(shí)現(xiàn)整個流程,必須搭建聯(lián)系人的服務(wù)器端,例程中在目錄samplesyncadapter_server中也提供了簡單的server端python代碼,需要搭建在google app engine上。搭建過程遇到一些問題,由于對python不熟我弄了幾天才解決好搭建成功,其中遇到的一個model moudle找不到的問題需要你在model中新建一個__init__.py的空文件,來說明是一個python模塊,如果你也遇到此問題,希望對你有幫助。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    精品熟女少妇一区二区三区| 欧美成人一区二区三区在线 | 99久久国产精品成人观看 | 91日韩欧美在线视频| 人妻内射精品一区二区| 欧美午夜一级特黄大片| 九九热在线视频观看最新| 亚洲精品小视频在线观看| 国产女性精品一区二区三区 | 少妇特黄av一区二区三区| 夫妻性生活动态图视频| 91国内视频一区二区三区| 日韩中文字幕狠狠人妻| 国产av一区二区三区久久不卡 | 午夜精品一区二区av| 国产亚洲欧美一区二区| 色好吊视频这里只有精| 国产成人亚洲欧美二区综| 搡老熟女老女人一区二区| 国产午夜在线精品视频| 夜夜躁狠狠躁日日躁视频黑人 | 亚洲天堂一区在线播放| 欧美成人高清在线播放| 成人欧美一区二区三区视频| 久久精品福利在线观看| 国产一级特黄在线观看| 日韩精品一区二区三区av在线| 亚洲视频一区自拍偷拍另类| 久久99国产精品果冻传媒| 国产精品亚洲综合天堂夜夜| 亚洲一区二区精品国产av | 搡老熟女老女人一区二区| 国产亚洲欧美日韩国亚语| 亚洲天堂精品一区二区| 欧美日韩人妻中文一区二区 | 人妻内射精品一区二区| 黄色国产自拍在线观看| 狠狠干狠狠操在线播放| 中文字幕免费观看亚洲视频| 精品欧美在线观看国产| 成人午夜爽爽爽免费视频|