当前位置: 首页 > news >正文

佛山市桂城建设局网站青岛seo优化

佛山市桂城建设局网站,青岛seo优化,wordpress投稿收费吗,做网站推广广告一. 了解服务(Service)的概念 service是安卓开发中一个很重要组件,意为“服务”。与我们常见的activity不同,“服务”是默默的在背后进行工作的,通常,它用于在后台为我们执行一些耗时,或者需要…

一. 了解服务(Service)的概念

service是安卓开发中一个很重要组件,意为“服务”。与我们常见的activity不同,“服务”是默默的在背后进行工作的,通常,它用于在后台为我们执行一些耗时,或者需要长时间执行的一些操作的。通常的,我们使用 Intent来启动一个服务(需要在manifest文件中注册,也可以像注册activity一样,给它分配进程)。Service可以不需要UI就在后台运行,不用管开启它的页面是否被销毁,只要进程还在就可以在后台运行。

 - Service生命周期:


public class MyService extends Service {@Overridepublic void onCreate() {super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return startCommandReturnId;}@Overridepublic void onDestroy() {super.onDestroy();}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}

 二. 问题背景

产品需要在我们的业务启动之后,在状态栏展示一个“xx应用正在进行中”中的一个通知,同时,要求app退后台后也不能被结束,即需要保活。于是,我们将目光投向了service

....// 业务启动流程结束
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && (guildInfo != null)) {getApp().applicationContext.startForegroundService(serviceIntent)
} else {getApp().applicationContext.startService(serviceIntent)}
// Service类中
public int onStartCommand(Intent intent, int flags, int startId) {....
mAudioNotification = createAudioNotification(); //创建通知栏展示内容
startForeground(NID, mAudioNotification); // 展示服务通知....
}

 于是我们的业务中出现了这样的代码,乍看之下 好像也没什么问题。可是外发之后,收到的crash反馈却只增不减。

Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord

 这类堆栈引起了我们的注意。原来我们使用了新提供的 startForegroundService,而这个API比较特殊,它要求我们在调用之后,收到 onStartCommand 回调后 5s内必须调用 startForeground, 否则会有ANR,而如果在调用 startForeground 之前,调用了 stopService 或者 stopSelf ,则会直接抛出 crash 我们这里问题的原因就是,在startForeground之前,调用了 stopService。问题找到了,是业务自己调用导致的。

但,似乎这个API没有提供给我们一个可以合适取消service的时机呢。既然这个API 限制这么多,我们又为什么要选择它呢?它和之前常用的startService又有什么区别呢?

三. 源代码分析

@Overridepublic ComponentName startService(Intent service) {warnIfCallingFromSystemProcess();return startServiceCommon(service, false, mUser);}@Overridepublic ComponentName startForegroundService(Intent service) {warnIfCallingFromSystemProcess();return startServiceCommon(service, true, mUser);}private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user)

 这两个API最终的都是调用的 startServiceCommon,区别只在于 其中的参数 requireForeground 字段赋值不同。那么这个字段究竟做了哪些处理呢?

在Android8.0的行为变更说明中,我们看到,不在允许随意创建 后台服务,所以改为 调用 startForegroundService的形式。

 

  1.  不满足条件(如:O以上版本后台启动服务)调用startService会抛异常
private ComponentName startServiceCommon(Intent service, boolean requireForeground,UserHandle user) {try {validateServiceIntent(service);service.prepareToLeaveProcess(this);ComponentName cn = ActivityManager.getService().startService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), requireForeground,getOpPackageName(), getAttributionTag(), user.getIdentifier());if (cn != null) {// 异常匹配if (cn.getPackageName().equals("!")) {throw new SecurityException("Not allowed to start service " + service+ " without permission " + cn.getClassName());} else if (cn.getPackageName().equals("!!")) {throw new SecurityException("Unable to start service " + service+ ": " + cn.getClassName());} else if (cn.getPackageName().equals("?")) {throw ServiceStartNotAllowedException.newInstance(requireForeground,"Not allowed to start service " + service + ": " + cn.getClassName());}}....return cn;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

if (forcedStandby || (!r.startRequested && !fgRequired)) {// 调用startService,(!r.startRequested && !fgRequired) 条件为truefinal int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);if (allowed != ActivityManager.APP_START_MODE_NORMAL) {if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {return null;}if (forcedStandby) {if (fgRequired) {return null;}}UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid);return new ComponentName("?", "app is in background uid " + uidRec);}}

// Unified app-op and target sdk check@GuardedBy(anyOf = {"this", "mProcLock"})int appRestrictedInBackgroundLOSP(int uid, String packageName, int packageTargetSdk) {// 安卓8限制if (packageTargetSdk >= Build.VERSION_CODES.O) {if (DEBUG_BACKGROUND_CHECK) {Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");}return ActivityManager.APP_START_MODE_DELAYED_RIGID;}.....}

2.  提高服务优先级

我们知道,在安卓系统内存紧张时,前台应用是有高优先级的,不会被清理掉。所以,我们需要将“不可见”的服务 升级为前台服务,前台服务是被认为用于已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。

所以 我们在启动service后,收到onStartCommand时,调用 startForeground,同时传入需要展示在前台的notification

3.  为什么调用startForgroundService后,再调用stop或者没有及时调用startForeground会crash/ANR呢?

startServiceCommon

-> AMS.startService

-> ActiveServices.startServiceLocked

-> startServiceInnerLocked

-> bringUpServiceLocked

->realStartServiceLocked

-> sendServiceArgsLocked

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,boolean oomAdjusted) throws TransactionTooLargeException {...ArrayList<ServiceStartArgs> args = new ArrayList<>();while (r.pendingStarts.size() > 0) {ServiceRecord.StartItem si = r.pendingStarts.remove(0);...if (r.fgRequired && !r.fgWaiting) {if (!r.isForeground) {<!--监听是否5S内startForeground-->scheduleServiceForegroundTransitionTimeoutLocked(r);} ...try {r.app.thread.scheduleServiceArgs(r, slice);}
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {if (r.app.mServices.numberOfExecutingServices() == 0 || r.app.getThread() == null) {return;}Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);msg.obj = r;r.fgWaiting = true;mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs);}
/*** How long the Context.startForegroundService() grace period is to get around to* calling Service.startForeground() before we generate ANR.*/volatile int mServiceStartForegroundTimeoutMs = DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS;

 修改 r.fgWaiting = true启动任务延迟TimeoutMs后发送 SERVICE_FOREGROUND_TIMEOUT_MSG

// handler处理 SERVICE_FOREGROUND_TIMEOUT_MSG
void serviceForegroundTimeout(ServiceRecord r) {ProcessRecord app;synchronized (mAm) {if (!r.fgRequired || !r.fgWaiting || r.destroying) {return;}app = r.app;if (app != null && app.isDebugging()) {// The app's being debugged; let it ridereturn;}if (DEBUG_BACKGROUND_CHECK) {Slog.i(TAG, "Service foreground-required timeout for " + r);}r.fgWaiting = false;stopServiceLocked(r, false);}if (app != null) {
// 就是我们之前遇到的异常final String annotation = "Context.startForegroundService() did not then call "+ "Service.startForeground(): " + r;Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_ANR_MSG);SomeArgs args = SomeArgs.obtain();args.arg1 = app;args.arg2 = annotation;msg.obj = args;mAm.mHandler.sendMessageDelayed(msg,mAm.mConstants.mServiceStartForegroundAnrDelayMs);}}

 如果在没有调用startForegroun前调用了stop,则会抛出 SERVICE_FOREGROUND_CRASH_MSG 的msg

private final void bringDownServiceLocked(ServiceRecord r) {...if (r.fgRequired) {r.fgRequired = false;r.fgWaiting = false;mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);if (r.app != null) {Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);msg.obj = r.app;msg.getData().putCharSequence(ActivityManagerService.SERVICE_RECORD_KEY, r.toString());mAm.mHandler.sendMessage(msg);}}

解决方案 -  startForegroundService后 必须按照要求调用 startForground 😊

四. 总结

笔者的业务场景下 其实不需要用这么严格的API,正常的在 应用处于前台时,启动前台服务 就按照常用的startService -> startForeground 调用即可。如果一定需要使用 startForegroundService 就要注意到以上的几个问题。

http://www.yidumall.com/news/62721.html

相关文章:

  • wordpress插件没有设置免费网站做seo
  • 备份管理wordpress优化网站标题
  • 东莞网页设计教程seo建设者
  • 网站开发哈尔滨网站开发公司电话百度网页电脑版入口
  • 个体工商户可以做网站备案吗泉州关键词排名工具
  • wordpress临时文件夹重庆排名优化整站优化
  • 广东卫视你会怎么做网站北京网站建设公司大全
  • 海门网站制作深圳网络营销运营
  • 制作公司网站用阿里云seo网络推广公司
  • 深圳做网站一个月多少钱品牌全网推广
  • 网站服务器ecs网络营销软文范例
  • 做好市场定位的方法seo流量软件
  • html网站模板免费下载天津网站快速排名提升
  • 河南省建设厅网站103新品牌推广方案
  • dtc建站服务亚马逊关键词优化怎么做
  • 大气环保网站模板百度应用平台
  • 做网站的公司有哪些天津百度推广
  • 嘉兴英文网站建设深圳推广公司介绍
  • 武汉企业建站公司重庆网站优化
  • 广州市番禺区网站优化推广seo
  • 网站优化排名网络营销理论基础有哪些
  • 网站怎么做适配需要多少钱
  • 做门的网站南宁在哪里推广网站
  • 重庆江北区网站建设公司推广app赚钱项目
  • 网站开发管理系统有哪些2023适合小学生的新闻事件
  • 淘宝联盟推广可以做网站吗青岛百度seo
  • 北京网站建设新闻bt磁力兔子引擎
  • 徐汇网站制作百度排名优化工具
  • 如何用Python网站开发seo搜索引擎优化原理
  • 怎样做展示型网站网站更换服务器对seo的影响