简介
我们在之前的BroadCast章节中写了动态BroadCast。但我们提过一笔BroadCast也有静态之分,而静态的BroadCast主要用于监听一些如:开机广播、SIM卡拨出插入等广播。这些广播都为静态注册广播事件。因此我们今天就以一个App监听Android开机广播为例子说明静态广播的使用方法以及如何收听开机广播。
课程目标
- 进一步使用Android Stduio如何模拟开机、关机;
- 了解AVD的冷启动、快速启动模式;
- 静态广播的写法;
- 开机广播的处理以及相应的权限-permission;
网上几乎所有的例子都没有讲清这个开机广播,Android的开机广播事件叫“android.intent.action.BOOT_COMPLETED”,为了Receive它你必须在全局的AndroidManifest里加入至少以下两个Permission。
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
同时,你不能只是简单按下Android Studio模拟器里的这个按钮
开始课程
设计一个静态Receiver
我们设计一个自己的Receiver。
<receiver
android:name="org.mk.android.demoreceivebootcomplete.BootCompleteReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
把这段xml放置于AndroidManifest.xml文件中并且设置相应的uses:permission,全设完后的AndroidManifest.xml文件如下
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DemoReceiveBootComplete"
tools:targetApi="31">
<receiver
android:name="org.mk.android.demoreceivebootcomplete.BootCompleteReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>
此处和网上到处乱抄甚至机器翻译的混乱的知识库有3处区别:
- 区别1:我们在uses:permission还要加入android.permission.WAKE_LOCK;
- 区别2:在receiver中需要指定全包路径而不是.BootCompleteReceiver这样的简写;
- 区别3:在receiver标签内还需要设android:permission;
下面来书写BootCompleteReceiver类
BootCompleteReceiver类
package org.mk.android.demoreceivebootcomplete;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.util.Log;
import android.view.WindowManager;
public class BootCompleteReceiver extends BroadcastReceiver {
public final static String TAG="mytag";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG,">>>>>>receive broadcast"+intent.getAction());
}
}
非常简单,只要监听到了手机开机,它就会打印一条LOG。
activiti_main.xml
Android Studio在new->empty activity时默认的hello world
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
Android Studio在new->empty activity时默认的hello world
package org.mk.android.demoreceivebootcomplete;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
如何运行看效果
网上又是一堆错的。
第一步操作:设置AVD高级模式
按照下图:
第二步操作:设置app开机模式为Cold boot模式
然后在下拉出的“Show Advanced Settings”里
把默认启动方式如果是“Quick boot”,那么请把它改成“Cold boot”。因为Quick boot是自动记录上一次手机的运行状态,它不能模拟真机的开关机。这个BOOT_COMPLETE事件就是在真正的关机开机时才发生的,举例来说,我长按着Android手机的顶部按钮10秒后卡断电源这样的关机后再开机才能触发这个BOOT_COMPLETE事件,而且只能触发一次。
如果只是短按一下手机顶部按钮->黑屏->再短按一下手机顶部按钮->亮屏,这种叫Quick boot,这种是不能触发BOOT_COMPLETE事件的。
因此网上的教程都没有说透这一个点,导致我们的初学者不知道配了多少个uses:permission、试了无数次就是无法触发这个BOOT_COMPLETE事件并浪费了大量的时间只为了触发一下这个事件的效果。
第三步操作:在AVD“已启动”模式下进行强制关机开机
你可以先把应用连同AVD先启动起来如下图,以下这样的状态就是AVD已启动模式。
用鼠标长按“开关”按钮直到出现以下第二个界面
点Restart按钮,出现以下界面
然后你要等一会,大概在15-30秒不等,然后你会得到这样的界面
最后在这个过渡界面再过2-3秒后,Android充分开机后你就可以收到以下这条消息了。
这就是Android真正的“开机收到开机广播”,网上教程统统没说清。每次你要触发这个“开机”事件,你可以每次在AVD已启动情况下点【Restart】按钮,这样才能每次触发和验证你要在开机事件被你安装在手机的APP监听到时才要去做的一些事
请自己动一下手吧。