Android账号同步系统的建立——AccountManager及其他相关类的运用
生活随笔
收集整理的這篇文章主要介紹了
Android账号同步系统的建立——AccountManager及其他相关类的运用
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、效果圖
1.1 Android設(shè)備->設(shè)置->賬戶與安全
1.2 點(diǎn)擊“賬戶標(biāo)簽DEMO”
如果“賬戶標(biāo)簽DEMO”此時(shí)只添加了一個(gè)賬號(hào)的話,點(diǎn)擊該條目之后將會(huì)直接進(jìn)入如下界面: 其中“369”就是賬戶名稱1.3 賬戶標(biāo)簽DEMO中添加了兩個(gè)賬號(hào)
如果“賬戶標(biāo)簽DEMO”此時(shí)只添加了多個(gè)賬號(hào)的話,點(diǎn)擊該條目之后將會(huì)直接進(jìn)入如下界面: 點(diǎn)擊相應(yīng)賬號(hào)條目之后就會(huì)進(jìn)入了1.2章節(jié)中的界面,不過(guò)“369”換成了相應(yīng)點(diǎn)擊賬號(hào)的名稱二、擼代碼
2.1 AccountManager的使用
申明權(quán)限 <uses-permission android:name="android.permission.GET_ACCOUNTS" /><uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" /><uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" /><uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/><uses-permission android:name="android.permission.USE_CREDENTIALS"/>在java代碼中使用AccountManager
package com.study.yang.accoutmanagerdemokotlinimport android.net.Uri import android.view.View import android.widget.ArrayAdapter import android.accounts.Account import android.accounts.AccountAuthenticatorActivity import android.accounts.AccountManager import android.content.* import android.os.*import com.study.yang.accoutmanagerdemokotlin.adapter.MyCursorAdapter import com.study.yang.accoutmanagerdemokotlin.data.DefineAccount import com.study.yang.accoutmanagerdemokotlin.provider.AUTHORITYimport kotlinx.android.synthetic.main.activity_login.* import java.util.*/*** I want to use Kotlin to implement the program,but* it's not good to use Kotlin here.*/ class LoginActivity : AccountAuthenticatorActivity() {private lateinit var accountManage: AccountManagerprivate val ACCOUNT_TYPE = "com.study.account"val accountStrings = arrayListOf<String>()var handler = object : Handler() {override fun handleMessage(msg: Message?) {super.handleMessage(msg)var account = msg?.obj as DefineAccounthandlerLoginResult(account.email, account.pwd)}}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_login)accountManage = getSystemService(Context.ACCOUNT_SERVICE) as AccountManager//根據(jù)賬戶類型獲取賬號(hào)accountManage.getAccountsByType(ACCOUNT_TYPE)?.takeIf {//判斷當(dāng)前獲取到的賬號(hào)列表是否為空it.isNotEmpty()}?.let {//可變參數(shù)時(shí)需要引入“*”號(hào)Arrays.asList(*it)}?.map {var account = it as AccountaccountStrings.add(it.name)if (it.name == "1") {val password = accountManage.getUserData(it, "password")val email = accountManage.getUserData(it, "account")println(password)println(email)/*** 更新相應(yīng)賬戶的UserData*/accountManage.setUserData(it, "password", "1111")}}/*** 給AutoCompleteTextView添加自動(dòng)提示功能*/email.setAdapter(ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, accountStrings))}/*** 登錄*/fun login(view: View) {val email = email.text.toString().trim()val password = password.text.toString().trim()val msg = handler.obtainMessage()var defineAccount = DefineAccount(email, password)msg.obj = defineAccounthandler.sendMessageDelayed(msg, 2000)}/*** 查詢用戶*/fun queryUser(view: View) {var uri = Uri.parse("content://com.study.account.provider/account")//cursor不能關(guān)閉,一旦關(guān)閉CursorAdapter自動(dòng)更新時(shí)將會(huì)報(bào)錯(cuò)//此處傳入的uri及其子層級(jí)的uri發(fā)生變動(dòng)的時(shí)候都會(huì)被更新val cursor = contentResolver.query(uri, null, null, null, null)var cursorAdapter = MyCursorAdapter(this, cursor)lv.adapter = cursorAdapter}/*** 處理登錄結(jié)果*/private fun handlerLoginResult(email: String, password: String) {val account = Account(email, ACCOUNT_TYPE)val userData = Bundle()userData.putString("account", email)userData.putString("password", "==$password==")userData.putString("auth_token", "")var uri = Uri.parse("content://com.study.account.provider/account")var values = ContentValues()values.put("email", email)values.put("pwd", "==$password==")contentResolver.insert(uri, values)/*** 添加賬戶,建立App的同步機(jī)制* 例如:* 在應(yīng)用中注冊(cè)能夠接受頻繁廣播事件的廣播,在某種程度上可以達(dá)到App包活的效果* 最好是設(shè)置自動(dòng)同步,自動(dòng)同步是由設(shè)備自動(dòng)觸發(fā)*/accountManage.addAccountExplicitly(account, password, userData)//自動(dòng)同步/*** 當(dāng)前賬號(hào)是否可同步,大于1意味著可以同步*/ContentResolver.setIsSyncable(account, AUTHORITY, 1)/*** 當(dāng)前賬號(hào)是否自動(dòng)同步*/ContentResolver.setSyncAutomatically(account, AUTHORITY, true)/*** 當(dāng)前賬號(hào)同步的頻率*/ContentResolver.addPeriodicSync(account, AUTHORITY, userData, 30)//手動(dòng)同步// ContentResolver.requestSync(account, AUTHORITY, userData)}}2.2 AbstractAccountAuthenticator的使用
這個(gè)類將會(huì)被繼承使用,不過(guò)需要配合Service使用。應(yīng)用啟動(dòng)時(shí)系統(tǒng)將會(huì)通過(guò) android:name="android.accounts.AccountAuthenticator"來(lái)啟動(dòng)AccountAuthenticatorService。AccountAuthenticatorService源碼如下所示:
package com.study.yang.accoutmanagerdemokotlin.serviceimport android.app.Service import android.content.Intent import android.os.IBinder import com.study.yang.accoutmanagerdemokotlin.authenticator.Authenticatorclass AccountAuthenticatorService : Service() {lateinit var authenticator: Authenticatoroverride fun onCreate() {super.onCreate()authenticator = Authenticator(this)}override fun onBind(intent: Intent): IBinder {return authenticator.iBinder}}在清單文件中配置AccountAuthenticatorService ,具體配置如下:
<serviceandroid:name=".service.AccountAuthenticatorService"android:enabled="true"android:exported="true"><intent-filter><!--這個(gè)Action是由系統(tǒng)提供的--><action android:name="android.accounts.AccountAuthenticator" /></intent-filter><meta-dataandroid:name="android.accounts.AccountAuthenticator"android:resource="@xml/authenticator" /></service>其中authenticator.xml具體內(nèi)容如下所示:
<?xml version="1.0" encoding="utf-8"?> <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"android:accountPreferences="@xml/account_preferences"android:accountType="com.study.account"android:icon="@drawable/ic_account_balance"android:label="@string/account_label"android:smallIcon="@drawable/ic_drafts_black"><!--android:accountPreferences這個(gè)屬性添加之后,當(dāng)只添加一個(gè)賬戶的時(shí)候也會(huì)顯示這個(gè)應(yīng)用中的應(yīng)用賬戶列表android:accountType的賬戶類型,具有唯一性android:icon和android:smallIcon都是展示圖標(biāo)的,不過(guò)大多數(shù)情況下都是顯示android:icon指定的圖標(biāo)android:label指定賬戶列表下對(duì)應(yīng)應(yīng)用的標(biāo)簽--> </account-authenticator>Authenticator繼承至AbstractAccountAuthenticator,具體源碼如下所示:
package com.study.yang.accoutmanagerdemokotlin.authenticatorimport android.accounts.AbstractAccountAuthenticator import android.accounts.Account import android.accounts.AccountAuthenticatorResponse import android.accounts.AccountManager import android.content.Context import android.content.Intent import android.os.Bundle import com.study.yang.accoutmanagerdemokotlin.LoginActivity import com.study.yang.accoutmanagerdemokotlin.Rclass Authenticator(context: Context) : AbstractAccountAuthenticator(context) {var context = context/*** 至于這個(gè)方法,沒(méi)有找到觸發(fā)的方式* 個(gè)人理解:是根據(jù)authTokenType獲取authenticator.xml中配置的android:label* 所以在這個(gè)地方賦值為@string/account_label*/override fun getAuthTokenLabel(authTokenType: String?): String {println("getAuthTokenLabel")return context.getString(R.string.account_label)}/*** accountManage.confirmCredentials(it, null, this@LoginActivity, null, null)* 調(diào)用confirmCredentials*/override fun confirmCredentials(response: AccountAuthenticatorResponse?, account: Account?, options: Bundle?): Bundle {println("confirmCredentials")return Bundle()}/*** accountManage.updateCredentials(it, ACCOUNT_TYPE, null, this@LoginActivity, null, null)*/override fun updateCredentials(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle {println("updateCredentials")return Bundle()}/*** accountManage.getAuthToken(it, ACCOUNT_TYPE, null, this@LoginActivity, null, null)* accountManage.blockingGetAuthToken(account, ACCOUNT_TYPE, true)* 都會(huì)調(diào)用getAuthToken方法,blockingGetAuthToken必須在子線程中調(diào)用,否則會(huì)造成死鎖*/override fun getAuthToken(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle {println("getAuthToken")return Bundle()}/*** accountManage.hasFeatures(it, features, null, null)*/override fun hasFeatures(response: AccountAuthenticatorResponse?, account: Account?, features: Array<out String>?): Bundle {println("hasFeatures")return Bundle()}/*** accountManage.editProperties(ACCOUNT_TYPE, this@LoginActivity, null, null)*/override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?): Bundle {println("editProperties")return Bundle()}/*** 該方法在手機(jī)中“設(shè)置->安全與賬戶->* 用戶和賬戶列表頁(yè)面點(diǎn)擊“添加”按鈕->* 添加賬戶列表->選中自己的應(yīng)用->* 調(diào)用addAccount方法”*/override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array<out String>?, options: Bundle?): Bundle {println("addAccount")val addAccountIntent = Intent(context, LoginActivity::class.java)addAccountIntent.putExtra("authTokenType", authTokenType)if (options != null) {addAccountIntent.putExtras(options)}//一定要把response傳入intent的extra中,便于將登錄操作的結(jié)果回調(diào)給AccountManageraddAccountIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response)var bundle = Bundle()bundle.putParcelable(AccountManager.KEY_INTENT, addAccountIntent)return bundle}}2.3 AbstractThreadedSyncAdapter使用
這個(gè)類將會(huì)被繼承使用,不過(guò)需要配合Service使用。應(yīng)用啟動(dòng)時(shí)系統(tǒng)將會(huì)通過(guò) android:name="android.content.SyncAdapter"來(lái)啟動(dòng)SyncAdapterService。SyncAdapterService源碼如下所示:
package com.study.yang.accoutmanagerdemokotlin.serviceimport android.app.Service import android.content.Intent import android.os.IBinder import com.study.yang.accoutmanagerdemokotlin.adapter.SyncAdapterclass SyncAdapterService : Service() {lateinit var syncAdapter: SyncAdapteroverride fun onCreate() {super.onCreate()syncAdapter = SyncAdapter(this, true)}override fun onBind(intent: Intent): IBinder {return syncAdapter.syncAdapterBinder} }在清單文件中配置SyncAdapterService ,具體配置如下:
<serviceandroid:name=".service.SyncAdapterService"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.content.SyncAdapter" /></intent-filter><meta-dataandroid:name="android.content.SyncAdapter"android:resource="@xml/sync_adapter" /></service>其中sync_adapter.xml具體內(nèi)容如下所示:
<?xml version="1.0" encoding="utf-8"?> <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"android:accountType="com.study.account"android:allowParallelSyncs="false"android:contentAuthority="com.study.account.provider"android:isAlwaysSyncable="true"android:supportsUploading="false"android:userVisible="false"><!--android:accountType跟authenticator.xml中的android:accountType一致android:allowParallelSyncs是否支持并行同步android:contentAuthority指定相應(yīng)內(nèi)容提供者的authorityandroid:isAlwaysSyncable是否支持同步android:supportsUploading是否支持上傳android:userVisible用戶是否可見(jiàn),false時(shí)用戶看不到APP的同步時(shí)間--> </sync-adapter>SyncAdapter繼承至AbstractThreadedSyncAdapter,具體源碼如下所示:
package com.study.yang.accoutmanagerdemokotlin.adapterimport android.accounts.Account import android.content.AbstractThreadedSyncAdapter import android.content.ContentProviderClient import android.content.Context import android.content.SyncResult import android.net.Uri import android.os.Bundleclass SyncAdapter(context: Context, autoInitialize: Boolean) : AbstractThreadedSyncAdapter(context, autoInitialize) {/*** 不管系統(tǒng)自動(dòng)同步還是手動(dòng)同步,都會(huì)調(diào)用這個(gè)方法* 在這個(gè)方法中可以處理與服務(wù)器交互從而同步數(shù)據(jù)** account:當(dāng)前同步的賬號(hào)* extras:同步的額外參數(shù),目前沒(méi)發(fā)現(xiàn)效果* authority:sync_adapter.xml中配置的contentAuthority的值* provider:與authority相匹配的ContentProvider的Client* syncResult:同步結(jié)果*/override fun onPerformSync(account: Account?, extras: Bundle?, authority: String?,provider: ContentProviderClient?, syncResult: SyncResult?) { // context.contentResolver.notifyChange()println("${account?.name}===${account?.type}")println("$authority")println(extras)var uri = Uri.parse("content://com.study.account.provider/account")val projections = arrayOf("email", "pwd")val cursor = provider?.query(uri, projections, "email=?", arrayOf(account?.name), null)cursor?.takeIf {it.count > 0}.let {it?.moveToFirst()println(it?.getString(it.getColumnIndex("pwd")))}}}源碼地址
總結(jié)
以上是生活随笔為你收集整理的Android账号同步系统的建立——AccountManager及其他相关类的运用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 无法显示 隐藏文件 无法启动 杀毒软件
- 下一篇: ERP 数据流脚本框架 Samsara