原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/Android/2019/0615/541.html
	安卓8.0手机线上报错:
	java.lang.IllegalStateException:Fatal Exception thrown on Scheduler.
	2io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.void run()(HandlerScheduler.java:111)
	3......
	4java.lang.IllegalStateException:Not allowed to start service Intent { cmp=com.xianglin.app/.biz.gold.service.StepService }: app is in background uid UidRecord{be88278 u0a36 SVC bg:+1m4s717ms idle procs:4 seq(0,0,0)}
	5android.app.ContextImpl.startServiceCo妹妹on(ContextImpl.java:1701)
	6android.app.ContextImpl.startService(ContextImpl.java:1657)
	7android.content.ContextWrapper.startService(ContextWrapper.java:644)
	8com.xianglin.app.utils.AppUtils.void setupService(android.content.Context)(AppUtils.java:479)
	9com.xianglin.app.utils.net.NetStateChangeReceiver$1.void onSuccess(com.xianglin.appserv.co妹妹on.service.facade.model.vo.LoginVo)(NetStateChangeReceiver.java:195)
	10com.xianglin.app.utils.net.NetStateChangeReceiver$1.void onSuccess(java.lang.Object)(NetStateChangeReceiver.java:191)
	错误缘故:
	Android 8.0 不再容许背景service干脆通过startService体例去启动, 具体举动变化如下:
	要是针对 Android 8.0 的运用测试在不容许其建立背景服无的环境下应用 startService() 函数,则该函数将激励一个 IllegalStateException。 新的 Context.startForegroundService() 函数将启动一个前台服无。当今,即便运用在背景运转, 体系也容许其挪用 Context.startForegroundService()。不过,运用必需在建立服无后的五秒内挪用该服无的 startForeground() 函数。
	办理要领:
	1. 点窜启动体例
	if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	context.startForegroundService(intent);
	} else {
	context.startService(intent);
	}
	2. 而且在service里再挪用startForeground要领,不然就会出现ANR
	?
	1
	context.startForeground(SERVICE_ID, builder.getNotification());
	校验下版本,startForeground(1, new Notification())放在oncreate()里就行。
	好了,题目办理。
	最近发现P也出了,就起了个P的虚拟机,另有版本27 8.1体系,后果提醒
	\
	android O 以后每个Notification都必要倚赖一个channel,要不然就报错。那就加一个简单的channel
	\
	\
	这里即是简单应用,并不做过量细化的操纵,具体可查阅NotificationChannel的用法,属性良多。
	参考
	https://stackoverflow.com/questions/46445265/android-8-0-java-lang-illegalstateexception-not-allowed-to-start-service-inten
	https://developer.android.com/about/versions/oreo/background
	Android O对运用在背景运转时可以执行的操纵施加了限制,称为背景执行限制(Background Execution Limits),这可以大大削减运用的内存应用和耗电量,进步用户体验。背景执行限制分为两个片面:背景服无限制(Background Service Limitations)、播送限制(BroadcastLimitations)。
	背景服无限制
	若何才算是背景运用?除了下面环境外都是背景运用
	1.具备可见的Activity
	2.具备前台服无
	3.另一个前台运用已相关到该运用(通过bindService大概应用该运用的ContentProvider)。
	当运用处于背景时:
	1.在背景运转的服无在几分钟内会被stop掉(模拟器测试在1分钟左右后被kill掉)。在这段光阴内,运用仍可以建立和应用服无。
	2.在运用处于背景几分钟后(模拟器测试1分钟左右),运用将不行再通过startService建立背景服无,要是建立则抛出以下最
	?
	1
	Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.samsung.test/.TestService }: app is in background
	运用处于背景时,固然不行通过startService建立背景服无,但仍可以通过下面的体例建立前台服无。
	?
	1
	NotificationManager noti = (NotificationManager)getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
	noti.startServiceInForeground();
	背景服无会被kill掉,官方保举可应用AlarmManager、SyncAdapter、JobScheduler取代背景服无。
	播送限制
	要是运用监听少许体系播送,当体系发出播送时,良多运用都邑被唤醒,这会招致所有运用疾速地连续花消资源,从而低落用户体验。其实,大片面运用都不会处分这个播送,运用只是唤醒一下看看和本人是否相关,为了缓和这一题目,Android N对少许播送做出了限制:
	1.targetSdkVersion为Android N(API level 24)及以上的运用,要是运用在AndroidManifest.xml中静态注册CONNECTIVITY_ACTION这个receiver,运用将不行收到此播送。要是运用应用Context.registerReceiver()动静注册receiver,运用仍可以收到这个播送。
	2.运转在Android N及以上建筑的运用,无论是targetSdkVersion是否是Android N,运用都不行发送大概汲取ACTION_NEW_PICTURE和ACTION_NEW_VIDEO这两个播送。
	在大无数环境下,运用都可以应用JobScheduler功课降服这些限制。 这种体例让运用放置为在未活跃运转时执行事情,不过仍能够使体系可以在不影响用户体验的环境下放置这些功课。
	Android 8.0 提供针对JobScheduler的多个改进,让您可以更放松地应用决策功课取代服无和播送汲取器;如需打听细致信息,请参阅JobScheduler 改进。
	而Android O执行了更为严格的限制。
	1.动静注册的receiver,可汲取任何显式和隐式播送。
	2.targetSdkVersion为Android O(API level 26)及以上的运用,静态注册的receiver将不行收到隐式播送,但可以收到显式播送。下面例子申明
	清单文件的receiver申明
	?
	1
	android:name=".TestReceiver"
	android:enabled="true">
	Receiver类定义
	?
	1
	public class TestReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
	Toast.makeText(context, "onReceive", Toast.LENGTH_SHORT).show();
	}
	}
	①要是如许发送隐式播送,receiver将汲取不到播送。
	?
	1
	Intent intent = new Intent();
	intent.setAction("com.test.example.testreceiver.action");
	sendBroadcast(intent);
	②要是如许发送显式播送,receiver仍可以汲取到播送
	?
	1
	Intent intent = new Intent();
	intent.setClassName("com.test.example.testreceiver", "com.test.example.testreceiver.TestReceiver");
	sendBroadcast(intent);
	固然静态注册的receiver不行汲取隐式播送,但Google考虑到少许播送也不频繁产生,也有少许例外,对这些例外的静态注册的receiver,仍可汲取隐式和显式播送。
	ACTION_LOCKED_BOOT_COMPLETED、ACTION_BOOT_COMPLETED
	ACTION_USER_INITIALIZE
	ACTION_TIMEZONE_CHANGED
	ACTION_LOCALE_CHANGED
	ACTION_USB_ACCESSORY_ATTACHED
	ACTION_USB_ACCESSORY_DETACHED
	ACTION_USB_DEVICE_ATTACHED
	ACTION_USB_DEVICE_DETACHED
	ACTION_HEADSET_PLUG
	……
	细目请参考
	https://developer.android.com/preview/features/background-broadcasts.html
	据Google工程师吐露,Google的目标是填塞一次电,手机可用2~3天,这也可看到Google在手机续航方面的起劲。
	当前惟有Android Studio2.4可以下载Android O 预览版SDK,下载地点
	https://dl.谷歌.com/dl/android/studio/ide-zips/2.4.0.6/android-studio-ide-171.3934896-windows.zip
	Android 8.0新特性-作废大片面静态注册播送
	本日楼主在写一个播送的demo,功效最的简单,即是一个运用发送一个自定义的播送,同时在这个运用内部定义了一个播送接受者,而且在AndroidManifest文件中进行静态的注册。Demo看上去最的简单,不过在Android 8.0的建筑运转这个运用,永远不行汲取到这个发送出去的播送,感受最的蒙蔽。环节是,在Android 7.0的建筑是能够汲取到的!
	1.缘故
	看到这个环境,我就觉得不是我的代码题目,应该是Android 8.0相较于Android 8.0以前的建筑有所变更,因而Google了一把,公然被我找到了题目所在。在Google爸爸的Android官网找到了Android 8.0举动变化的先容,此中有一句说的是:
	\
	这句话的意思即是说,在Android 8.0的平台上,运用不行对大片面的播送进行静态注册,也即是说,不行在AndroidManifest文件对有些播送进行静态注册,这里必需夸大是有些播送,由于有些播送照旧能够注册的。好比,经过楼主测试,对汲取Android 开机的播送通过静态注册照旧能够平常汲取的。
	Android 8.0举动变化的先容链接:https://developer.android.com/about/versions/oreo/android-8.0-changes.htmlhl=zh-cn,前面那个链接必需通过FQ,固然我们首倡科学上网,以是国内镜像网站链接:https://developer.android.谷歌.cn/about/versions/oreo/android-8.0.html。
	2.办理办法
	前面我们晓得了是甚么缘故招致的,只要晓得了缘故,办理办法就最轻易的想出来的。
	我们晓得播送的注册体例分为两种:
	A.静态注册,也即是说在AndroidManifest文件中对BroadcastReceiver进行注册,平时还会加上action用来过滤。
	B.动静注册,挪用Context中的registerReceiver对播送进行动静注册,应用unRegisterReceiver要领对播送进行作废注册的操纵。
	静态注册不行的话,那我们就动静注册啊!
	3.代码
	MainActivity文件的代码
	?
	1
	2
	3
	4
	5
	6
	7
	8
	9
	10
	11
	12
	13
	14
	15
	16
	17
	18
	19
	20
	21
	22
	23
	24
	25
	26
	27
	28
	29
	30
	31
	32
	33
	34
	35
	36
	37
	38
	1 public class MainActivity extends AppCompatActivity {
	 2
	 3  private Button mButton = null;
	 4
	 5  private IntentFilter mIntentFilter = null;
	 6
	 7  private MyBroadcastReceiver mMyBroadcastRecvier = null;
	 8
	 9
	10  @Override
	11  protected void onCreate(Bundle savedInstanceState) {
	12super.onCreate(savedInstanceState);
	13setContentView(R.layout.activity_main);
	14
	15//过滤器
	16mIntentFilter = new IntentFilter("pby");
	17//建立播送汲取者的工具
	18mMyBroadcastRecvier =  new MyBroadcastReceiver();
	19//注册播送汲取者的工具
	20registerReceiver(mMyBroadcastRecvier, mIntentFilter);
	21mButton = (Button) findViewById(R.id.id_button);
	22mButton.setOnClickListener(new View.OnClickListener(){
	23 @Override
	24 public void onClick(View v) {
	25  Intent intent = new Intent("pby");
	26  //发送一个播送
	27  sendBroadcast(intent);
	28 }
	29});
	30  }
	31
	32  @Override
	33  protected void onDestroy() {
	34super.onDestroy();
	35//作废播送汲取者的注册
	36unregisterReceiver(mMyBroadcastRecvier);
	37  }
	38 }
	MyBroadcastReceiver文件的代码
	?
	1
	2
	3
	4
	5
	6
	1 public class MyBroadcastReceiver extends BroadcastReceiver {
	2  @Override
	3  public void onReceive(Context context, Intent intent) {
	4Toast.makeText(context, "收到了自定义的播送", Toast.LENGTH_LONG).show();
	5  }
	6 }
	惟有上头的简单配置,没有点窜AndroidManifest文件中任何的代码
上篇:上一篇:修改ro属性的小工具新版本-170119
下篇:下一篇:Android 获取唯一机械码的代码

