Android8.0的新特性值得注意一下,不然会出现很多莫名的问题。。。
后台执行限制
Android 8.0 为提高电池续航时间而引入的变更之一是,当您的应用进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁。
此外,为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:
现在,在后台运行的应用对后台服务的访问受到限制。
应用无法使用其清单注册大部分隐式广播(即,并非专门针对此应用的广播)。
默认情况下,这些限制仅适用于针对 O 的应用。不过,用户可以从 Settings 屏幕为任意应用启用这些限制,即使应用并不是以 O 为目标平台。
Android 8.0 还对特定函数做出了以下变更:
如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException。
新的 Context.startForegroundService() 函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。
以下这个就是Android8.0的后台限制新特性导致的,果然要踩过坑,才印象深刻。
自己编写了一个demo跟踪广播的发送流程。
demo:注册一个静态receiver,然后发送广播。
Activity中发送广播的代码:
public class MainActivity extends Activity {
public static final String TAG = "TEST";
public final String TEST_ACTION = "com.maureen.test.TEST_ACTION";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"onResume");
Log.d(TAG,">>sendBroadcast");
Intent intent = new Intent(TEST_ACTION);
sendBroadcast(intent);
Log.d(TAG,"<);
}
private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG,"Dynamic receiver:action="+action);
}
};
}
AndroidManifest.xml中注册静态receiver:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.atc6111.testswitchicon">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MyTestReceiver">
<intent-filter>
<action android:name="com.maureen.test.TEST_ACTION"/>
</intent-filter>
</receiver>
</application>
</manifest>
Receiver对应的java文件:
public class MyTestReceiver extends BroadcastReceiver {
private final String TAG = "TEST-MyTestReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Static receiver:action=" + intent.getAction());
}
}
好的,现在开始运行这个demo。结果这个receiver一直都没有收到广播。。。。。
查看log,发现了warning信息:
W BroadcastQueue: Background execution not allowed: receiving Intent { act=com.maureen.test.TEST_ACTION flg=0x10 } to com.example.atc6111.testswitchicon/.MyTestReceiver
“Background execution not allowed” 打印出该warning的代码:
即是以下两种情况静态receiver不会接收到广播:
发送的intent设置了FLAG --FLAG_RECEIVER_EXCLUDE_BACKGROUND;
以下情况的均满足时:
①intent没有指定接收组件,也就是没有setComponent
②intent没有执行接收的package,也就是没有setPackage
③发送的intent没有设置FLAG-FLAG_RECEIVER_INCLUDE_BACKGROUND
④给定的权限并不都是签名权限。
根据这两种情况,即是说静态receiver接收不了隐式广播。本来打算采用最简单的方法添加Flag来解决的。
但是奇怪的是,Android Studio里没有FLAG_RECEIVER_INCLUDE_BACKGROUND!!!!
然后,只好在发送intent的时候setPackage。
@Override
protected void onResume() {
super.onResume();
Log.d(TAG,"onResume");
Log.d(TAG,">>sendBroadcast");
Intent intent = new Intent(TEST_ACTION);
intent.setPackage(getPackageName());
sendBroadcast(intent);
Log.d(TAG,"<);
}
修改之后,静态Receiver就能收到广播了。
但是如果就是想让静态receiver接收到隐式广播呢?应该还有其他方法,待学。。。。