金水郑州网站建设,台州做网站优化,长沙网站备案拍照点,网站建设需注意哪些事项账户同步的作用 : 如果应用的数据发生了改变 , 可以通过账户进行同步 , 进而与服务器进行数据同步操作 , 执行同步时 , 系统会拉活对应的应用进程 ;
实现的话#xff0c;主要是应用 APP 中可以注册 账户服务 Service , 应用安装后 , 如果系统发现应用中有该类型…账户同步的作用 : 如果应用的数据发生了改变 , 可以通过账户进行同步 , 进而与服务器进行数据同步操作 , 执行同步时 , 系统会拉活对应的应用进程 ;
实现的话主要是应用 APP 中可以注册 账户服务 Service , 应用安装后 , 如果系统发现应用中有该类型服务 , 就会为该应用开放添加账户的功能 ;
系统通过 Binder 机制 , 操作用户的 账户服务 Service ;
第三方应用可以通过该账户服务 , 将数据同步 到服务器中 ;
系统在进行应用账户同步时 , 会自动将对应的应用拉活 ;
Google 官方提供了账户同步案例 , https://github.com/googlearchive/android-BasicSyncAdapter , 已经停止维护了 , 但是项目还是有参考价值的 ; ( 源码放在了本博客的资源文件中 )
在上述项目中指向了推荐的后台任务示例 https://github.com/android/background-tasks-samples ; ( 源码放在了本博客的资源文件中 )
说白了进程拉活只是账户同步的附带作用 ;
具体实现:
1.创建一个账号同步工具类
public class AccountUtil {private static final String TAG AccountHelper;private static final String ACCOUNT_TYPE com.example.appprocesskeepalive.accounttype;private static final String ACCOUNT_AUTHORITY com.example.appprocesskeepalive.provider;private static final String ACCOUNT_NAME app账号同步demo;/*** 添加账号* param context*/public static void addAccount(Context context) {AccountManager accountManager (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);// 获得此类型的账户// 需要增加权限 GET_ACCOUNTSAccount[] accounts accountManager.getAccountsByType(ACCOUNT_TYPE);if (accounts.length 0) {Log.e(TAG, 账户已存在);return;}Account account new Account(ACCOUNT_NAME, ACCOUNT_TYPE);// 给这个账户类型添加一个账户// 需要增加权限 AUTHENTICATE_ACCOUNTSaccountManager.addAccountExplicitly(account, xx, new Bundle());}/*** 设置账户自动同步*/public static void sync() {Account account new Account(ACCOUNT_NAME, ACCOUNT_TYPE);// 下面三个都需要同一个权限 WRITE_SYNC_SETTINGS// 设置同步ContentResolver.setIsSyncable(account, ACCOUNT_AUTHORITY, 1);// 自动同步ContentResolver.setSyncAutomatically(account, ACCOUNT_AUTHORITY, true);// 设置同步周期ContentResolver.addPeriodicSync(account, ACCOUNT_AUTHORITY, new Bundle(), 1);}}
2.账号服务注册
注册一个服务 , 该服务的 onBind 方法返回 AbstractAccountAuthenticator 对象的 Binder , 只要该应用安装 , 就可以在 设置 - 账号 中查看该应用的账号
public class AuthService extends Service {private AccountAuthenticator accountAuthenticator;NullableOverridepublic IBinder onBind(Intent intent) {return accountAuthenticator.getIBinder();}Overridepublic void onCreate() {super.onCreate();accountAuthenticator new AccountAuthenticator(this);}public static class AccountAuthenticator extends AbstractAccountAuthenticator {private Context mContext;public AccountAuthenticator(Context context) {super(context);mContextcontext;}Overridepublic Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {return null;}Overridepublic Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType,String[] requiredFeatures, Bundle options) throws NetworkErrorException {AccountUtil.addAccount(mContext);AccountUtil.sync();return null;}Overridepublic Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,Bundle options) throws NetworkErrorException {return null;}Overridepublic Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,String authTokenType, Bundle options) throws NetworkErrorException {return null;}Overridepublic String getAuthTokenLabel(String authTokenType) {return null;}Overridepublic Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,String authTokenType, Bundle options) throws NetworkErrorException {return null;}Overridepublic Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,String[] features) throws NetworkErrorException {return null;}}
}3.注册一个ContentProvider
public class SyncProvider extends ContentProvider {Overridepublic boolean onCreate() {return false;}NullableOverridepublic Cursor query(NonNull Uri uri, Nullable String[] projection, Nullable String selection, Nullable String[] selectionArgs, Nullable String sortOrder) {return null;}NullableOverridepublic String getType(NonNull Uri uri) {return null;}NullableOverridepublic Uri insert(NonNull Uri uri, Nullable ContentValues values) {return null;}Overridepublic int delete(NonNull Uri uri, Nullable String selection, Nullable String[] selectionArgs) {return 0;}Overridepublic int update(NonNull Uri uri, Nullable ContentValues values, Nullable String selection, Nullable String[] selectionArgs) {return 0;}
}
4. 注册一个服务这个服务提供一个Action给系统以便系统能找到它然后就是继承和实现AbstractThreadedSyncAdapter此类中包含实现了ISyncAdapter.Stub内部类这个内部类封装了远程接口调用
public class SyncService extends Service {private SyncAdapter mSyncAdapter;private static final String TAG SyncService;NullableOverridepublic IBinder onBind(Intent intent) {return mSyncAdapter.getSyncAdapterBinder();}Overridepublic void onCreate() {super.onCreate();mSyncAdapter new SyncAdapter(getApplicationContext(), true);}public class SyncAdapter extends AbstractThreadedSyncAdapter {public SyncAdapter(Context context, boolean autoInitialize) {super(context, autoInitialize);}Overridepublic void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {// 账户同步操作// 与数据库 , 服务器同步操作 , 这里只是为了应用进程拉活 , 不实现具体的逻辑Log.i(AccountSyncService, 账户同步拉活激活);Log.i(AccountSyncService,是否还在运行:isServiceRunning(App.instance,com.example.appprocesskeepalive.WakeUpService));Intent intentnew Intent(App.instance, WakeUpService.class);if(Build.VERSION.SDK_INT Build.VERSION_CODES.O){ContextCompat.startForegroundService(App.instance, intent);}else {startService(intent);}}}public static boolean isServiceRunning(Context context, String serviceName) {ActivityManager activityManager (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);ListActivityManager.RunningServiceInfo runningServices activityManager.getRunningServices(Integer.MAX_VALUE);if (runningServices ! null) {for (ActivityManager.RunningServiceInfo serviceInfo : runningServices) {if (serviceInfo.service.getClassName().equals(serviceName)) {return true;}}}return false;}}
核心也是这块onPerformSync收到账号同步的回调收到后启动一个前台Service
public class WakeUpService extends Service {Overridepublic IBinder onBind(Intent intent) {return null;}Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 在这里启动你的应用startForeground(110, getNotification());Intent intent2 getPackageManager().getLaunchIntentForPackage(com.example.appprocesskeepalive);if (intent2 ! null) {//setFlags看自己情况使用也可以不调用intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);getApplication().startActivity(intent2);}return START_STICKY;}Overridepublic void onCreate() {super.onCreate();createNotificationChannel();}private void createNotificationChannel() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.O) {CharSequence name My Foreground Service Channel;String description This channel is used for my foreground service;int importance NotificationManager.IMPORTANCE_DEFAULT;NotificationChannel channel new NotificationChannel(测试保活, name, importance);channel.setDescription(description);NotificationManager notificationManager getSystemService(NotificationManager.class);notificationManager.createNotificationChannel(channel);}}private Notification getNotification() {Intent notificationIntent new Intent(this, MainActivity.class);PendingIntent pendingIntent PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);return new NotificationCompat.Builder(this, 测试保活).setContentTitle(My Foreground Service).setContentText(Running...).setSmallIcon(R.drawable.ic_launcher_background).setContentIntent(pendingIntent).build();}}
在service中启动一个activity但是要注意的是如果要启动activity的话需要申请一个悬浮窗权限 uses-permission android:nameandroid.permission.SYSTEM_ALERT_WINDOW / 然后就是配置文件的注册了 serviceandroid:name.auth.AuthServiceandroid:enabledtrueandroid:exportedtrueintent-filteraction android:nameandroid.accounts.AccountAuthenticator //intent-filtermeta-dataandroid:nameandroid.accounts.AccountAuthenticatorandroid:resourcexml/account_auth //serviceserviceandroid:name.auth.SyncServiceandroid:enabledtrueandroid:exportedtrueintent-filteraction android:nameandroid.content.SyncAdapter //intent-filtermeta-dataandroid:nameandroid.content.SyncAdapterandroid:resourcexml/up //serviceproviderandroid:name.auth.SyncProviderandroid:authoritiesstring/account_authorityandroid:exportedfalseandroid:syncabletrue /serviceandroid:name.WakeUpServiceandroid:enabledtrueandroid:exportedtrueandroid:persistenttrueandroid:stopWithTaskfalse /
其中 android:persistent是表示app常驻内存的意思虽然其实没啥大作用app被杀死了后它服务该死还是得死--
account_auth.xml
?xml version1.0 encodingutf-8?
account-authenticator xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:labelstring/app_nameandroid:iconmipmap/ic_launcherandroid:accountTypestring/account_typeandroid:smallIconmipmap/ic_launcher/
这块是用来配置账号同步在设置界面的UI显示的要注意的时候此处的accountType要跟AbstractAccountAuthenticator执行创建账号、同步账号时的accountType要一样
up.xml
?xml version1.0 encodingutf-8?
sync-adapter xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:accountTypestring/account_typeandroid:contentAuthoritystring/account_authorityandroid:userVisibletrueandroid:supportsUploadingfalseandroid:allowParallelSyncsfalseandroid:isAlwaysSyncabletrue/
!-- android:isAlwaysSyncable 属性 , 表示该账户同步操作 , 是否总是同步 , 这里设置 true , 账户拉活 , 越频繁越好 ;--
!-- android:userVisible 属性 , 表示是否在 设置 - 账号 界面 , 展示一个账户同步开关 , 这里选择 false , 不给用户展示 , 万一用户给关了 , 就无法进行账户拉活应用进程操作 ;--
写的可能有点乱具体实现在这个demo
AppProcessKeepAlive: 进程保活来的