做网站鞍山微信拼团小程序怎么做
装过Android版的Facebook、lastfm的同学是否对于这些应用的功能感到惊喜,它们可以定期更新朋友的最新信息,将最新近况和心情短语集成入联系人中。这些应用全部是以Android2.0后的账户和同步机制为基础的。Google的例程中给出了名为SampleSyncAdpater的例子,通过分析该例子可以学会Android中的Account验证、同步Adapter的使用。
详细例子代码可以看sdk samples中提供的源码,现在拿2.2中的版本来简要说明。
 
首先是 class Authenticator extends AbstractAccountAuthenticator ,该类是账户认证类,打开手机的Setting里,有Account&Sync 一项,Authenticator就是实现其中的账号功能的类。
- // in Authenticator.java
 - public Bundle addAccount(AccountAuthenticatorResponse response,
 - String accountType, String authTokenType, String[] requiredFeatures,
 - Bundle options) {
 - final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
 - intent.putExtra(AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE,
 - authTokenType);
 - intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
 - response);
 - final Bundle bundle = new Bundle();
 - bundle.putParcelable(AccountManager.KEY_INTENT, intent);
 - return bundle;
 - }
 
其中addAccount方法用来定义需要增加账号时的操作,如调用AuthenticatorActivity来进行账号的添加认证。
在AuthenticatorActivity.java中定义了handleLogin(),此方法由login_activity.xml中的android:onClick="handleLogin"定义与ui中的okbutton的关联。
- // in layout/login_activity.xml
 - <Button
 - android:id="@+id/ok_button"
 - android:layout_width="wrap_content"
 - android:layout_height="wrap_content"
 - android:layout_gravity="center_horizontal"
 - android:minWidth="100dip"
 - android:text="@string/login_activity_ok_button"
 - 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中再次尝试验证。
- // AuthenticatorActivity.java中的handleLogin()方法
 - /**
 - * Handles onClick event on the Submit button. Sends username/password to
 - * the server for authentication.
 - *
 - * @param view The Submit button for which this method is invoked
 - */
 - public void handleLogin(View view) {
 - if (mRequestNewAccount) {
 - mUsername = mUsernameEdit.getText().toString();
 - }
 - mPassword = mPasswordEdit.getText().toString();
 - if (TextUtils.isEmpty(mUsername) || TextUtils.isEmpty(mPassword)) {
 - mMessage.setText(getMessage());
 - } else {
 - showProgress();
 - // Start authenticating...
 - mAuthThread =
 - NetworkUtilities.attemptAuth(mUsername, mPassword, mHandler,
 - AuthenticatorActivity.this);
 - }
 - }
 
- // NetworkUtilities中的authenticate()方法通过网络访问具体来实现服务端的验证,sendResult()来使调用结果被AuthenticatorActivity的onAuthenticationResult()调用。
 - /**
 - * Connects to the Voiper server, authenticates the provided username and
 - * password.
 - *
 - * @param username The user's username
 - * @param password The user's password
 - * @param handler The hander instance from the calling UI thread.
 - * @param context The context of the calling Activity.
 - * @return boolean The boolean result indicating whether the user was
 - * successfully authenticated.
 - */
 - public static boolean authenticate(String username, String password,
 - Handler handler, final Context context) {
 - final HttpResponse resp;
 - final ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
 - params.add(new BasicNameValuePair(PARAM_USERNAME, username));
 - params.add(new BasicNameValuePair(PARAM_PASSWORD, password));
 - HttpEntity entity = null;
 - try {
 - entity = new UrlEncodedFormEntity(params);
 - } catch (final UnsupportedEncodingException e) {
 - // this should never happen.
 - throw new AssertionError(e);
 - }
 - final HttpPost post = new HttpPost(AUTH_URI);
 - post.addHeader(entity.getContentType());
 - post.setEntity(entity);
 - maybeCreateHttpClient();
 - try {
 - resp = mHttpClient.execute(post);
 - if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
 - if (Log.isLoggable(TAG, Log.VERBOSE)) {
 - Log.v(TAG, "Successful authentication");
 - }
 - sendResult(true, handler, context);
 - return true;
 - } else {
 - if (Log.isLoggable(TAG, Log.VERBOSE)) {
 - Log.v(TAG, "Error authenticating" + resp.getStatusLine());
 - }
 - sendResult(false, handler, context);
 - return false;
 - }
 - } catch (final IOException e) {
 - if (Log.isLoggable(TAG, Log.VERBOSE)) {
 - Log.v(TAG, "IOException when getting authtoken", e);
 - }
 - sendResult(false, handler, context);
 - return false;
 - } finally {
 - if (Log.isLoggable(TAG, Log.VERBOSE)) {
 - Log.v(TAG, "getAuthtoken completing");
 - }
 - }
 - }
 - /**
 - * Sends the authentication response from server back to the caller main UI
 - * thread through its handler.
 - *
 - * @param result The boolean holding authentication result
 - * @param handler The main UI thread's handler instance.
 - * @param context The caller Activity's context.
 - */
 - private static void sendResult(final Boolean result, final Handler handler,
 - final Context context) {
 - if (handler == null || context == null) {
 - return;
 - }
 - handler.post(new Runnable() {
 - public void run() {
 - ((AuthenticatorActivity) context).onAuthenticationResult(result);
 - }
 - });
 - }
 
- // AuthenticatorActivity.java中的onAuthenticationResult,来根据验证结果来选择结束认证或重新尝试。
 - /**
 - * Called when the authentication process completes (see attemptLogin()).
 - */
 - public void onAuthenticationResult(boolean result) {
 - Log.i(TAG, "onAuthenticationResult(" + result + ")");
 - // Hide the progress dialog
 - hideProgress();
 - if (result) {
 - if (!mConfirmCredentials) {
 - finishLogin();
 - } else {
 - finishConfirmCredentials(true);
 - }
 - } else {
 - Log.e(TAG, "onAuthenticationResult: failed to authenticate");
 - if (mRequestNewAccount) {
 - // "Please enter a valid username/password.
 - mMessage
 - .setText(getText(R.string.login_activity_loginfail_text_both));
 - } else {
 - // "Please enter a valid password." (Used when the
 - // account is already in the database but the password
 - // doesn't work.)
 - mMessage
 - .setText(getText(R.string.login_activity_loginfail_text_pwonly));
 - }
 - }
 - }
 
Account的验证完毕后,就生成了账号,可以开始使用同步功能了。同步的主要逻辑在public class SyncAdapter extends AbstractThreadedSyncAdapter中实现。
- // SyncAdapter.java中的OnPerformSync方法,主要的同步逻辑
 - @Override
 - public void onPerformSync(Account account, Bundle extras, String authority,
 - ContentProviderClient provider, SyncResult syncResult) {
 - List<User> users;
 - List<Status> statuses;
 - String authtoken = null;
 - try {
 - // use the account manager to request the credentials
 - authtoken =
 - mAccountManager.blockingGetAuthToken(account,
 - Constants.AUTHTOKEN_TYPE, true /* notifyAuthFailure */);
 - // fetch updates from the sample service over the cloud
 - users =
 - NetworkUtilities.fetchFriendUpdates(account, authtoken,
 - mLastUpdated);
 - // update the last synced date.
 - mLastUpdated = new Date();
 - // update platform contacts.
 - Log.d(TAG, "Calling contactManager's sync contacts");
 - ContactManager.syncContacts(mContext, account.name, users);
 - // fetch and update status messages for all the synced users.
 - statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken);
 - ContactManager.insertStatuses(mContext, account.name, statuses);
 - } catch (final AuthenticatorException e) {
 - syncResult.stats.numParseExceptions++;
 - Log.e(TAG, "AuthenticatorException", e);
 - } catch (final OperationCanceledException e) {
 - Log.e(TAG, "OperationCanceledExcetpion", e);
 - } catch (final IOException e) {
 - Log.e(TAG, "IOException", e);
 - syncResult.stats.numIoExceptions++;
 - } catch (final AuthenticationException e) {
 - mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE,
 - authtoken);
 - syncResult.stats.numAuthExceptions++;
 - Log.e(TAG, "AuthenticationException", e);
 - } catch (final ParseException e) {
 - syncResult.stats.numParseExceptions++;
 - Log.e(TAG, "ParseException", e);
 - } catch (final JSONException e) {
 - syncResult.stats.numParseExceptions++;
 - Log.e(TAG, "JSONException", e);
 - }
 - }
 
onPerformSync中的执行流程中,使用NetworkUtilities中的fetchFriendUpdates和fetchFriendStatuses来访问服务端的联系人更新,并使用了例程中自己封装的ContactManager来读取、更新联系人信息。
那Account和SyncAdapter及其Service和xml定义之间是如何关联的呢? AndroidManifest.xml中定义了AccountAuthenticator,SyncAdapter及对应的Service和xml定义的关联。
- <application
 - android:icon="@drawable/icon"
 - android:label="@string/label">
 - <!-- The authenticator service -->
 - <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>
 - <service
 - android:name=".syncadapter.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>
 - <activity
 - android:name=".authenticator.AuthenticatorActivity"
 - android:label="@string/ui_activity_title"
 - android:theme="@android:style/Theme.Dialog"
 - android:excludeFromRecents="true"
 - >
 - <!--
 - No intent-filter here! This activity is only ever launched by
 - someone who explicitly knows the class name
 - -->
 - </activity>
 - </application>
 
更详细的代码细节和执行流程,可以去把SDK中的SampleSyncAdapter代码运行起来体会一下,不过要实现整个流程,必须搭建联系人的服务器端,例程中在目录samplesyncadapter_server中也提供了简单的server端python代码,需要搭建在google app engine上。搭建过程遇到一些问题,由于对python不熟我弄了几天才解决好搭建成功,其中遇到的一个model moudle找不到的问题需要你在model中新建一个__init__.py的空文件,来说明是一个python模块,如果你也遇到此问题,希望对你有帮助。
