Android内置了很多系统级别的广播,我们可以在应用序中通过监听这些广播来得到各种系统的状态信息,比如手机开机完成后会发出一条广播、电池的电最发生变化会发出一条广播、时间或时区发生改变也会发出一条广播等。
想要实现广播的接收,就需要使用广播按收者。广播接收者可以自由地对自己感兴趣的进行注册。当有相应的广播发出时,广播接收者就能够收到该广播。并在内部处理相应的逻辑,注册广播的方式一般有两种,在代码中注册和在 AndroidManifest.xml中注册,其中的前者被称为动态注册,后者被称为静态注册。下面分别通过检测电话状态(动态注册)以及应用开机自动(静态注册)两个实例来讲解系统广播的具体用法。
动态注册广播实例
这里通过一个检测电话状态的实例来讲解如何动态注册广播。在实例中如果想要接收到这些电话状态的广播就需要使用广播接收者。实现一个广播接收者只需要新建一个继承自BroadcastReceiver 类的子类并重写父类的 onReceive()方法就行了。这样当有广播到来时. onRceive()方法就会得到执行,具体的业务逻编只需在onReceive()方法中处理或可以了。
下面我们通过来看实例代码,新建一个Activity类,动态注册广播。当然这里需要注意权限问题,读取电话状态是一个危险权限,除了要在AndroidManifest.xml文件中加入如下代码:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>复制代码还需要动态获取相关权限,下面是MainActivity的代码:
package com.rfstar.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.ActivityCompat;import androidx.core.content.ContextCompat;import android.Manifest;import android.content.Context;import android.content.IntentFilter;import android.content.pm.PackageManager;import android.os.Build;import android.os.Bundle;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private CallReceiver callReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getPermission(); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(callReceiver); } private void setCallReceiver() { callReceiver=new CallReceiver(); IntentFilter filter=new IntentFilter(); filter.addAction("android.intent.action.PHONE_STATE"); filter.addAction("android.intent.action.NEW_OUTGOING_CALL"); registerReceiver(callReceiver,filter); } private void getPermission() { //判断版本号,在api23也就是6.0版本之前能直接获得权限 if(Build.VERSION.SDK_INT>=23) { int checkCALLPermission= ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE); int checkOutCALLPermission=ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS); //判断是否具有权限 if(checkCALLPermission!= PackageManager.PERMISSION_GRANTED||checkOutCALLPermission!=PackageManager.PERMISSION_GRANTED) { //用以申请权限的方法,此时使用ActivityCompat类的该方法,以便于版本兼容 ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.PROCESS_OUTGOING_CALLS},1); return; }else{ //如果已经获取了相关权限,调用initData()与initView()方法 setCallReceiver(); } } else{ //如果api版本低于23,直接调用initData()与initView()方法 setCallReceiver(); } } //申请权限做出响应后的回调函数 public void onRequestPermissonsResult(int requestCode,String[] permissions,int[] grantResults) { switch (requestCode) { case 1: if(grantResults[0]==PackageManager.PERMISSION_GRANTED){ Toast.makeText(this,"获取权限成功",Toast.LENGTH_SHORT).show(); //获取权限成功,动态注册广播接收者 setCallReceiver(); }else{ Toast.makeText(this,"获取权限失败",Toast.LENGTH_SHORT).show(); } break; default: super.onRequestPermissionsResult(requestCode,permissions,grantResults); } }}复制代码在Activity 类中包括两部分内容∶一部分是动态获取权限,一部分是动态注册广播。这里只讲解动态注册广播。首先我们创建一个 IntentFilter实例,并为其添加一个值为android.intent.action.PHONE_STATE 的 action。接下来创建一个CallReceiver 实例,然后调用registerReceiver()方法进行注册,将CallReceiver的实例和 IntentFilter的实例都传进去,这样CallReceiver就会收到所有值为 android.intent.action.PHONE_STATE 的广播,也就实现了监听电语状态的功能。一般情况下,动态注册的广播接收器一定要取消注册才行,取消注册通过在
onDestroy()方法中通过调用 unregisterReceiver()方法来实现。
新建一个继承自BroadcastReceiver类的CallReceiver类,用来获得用户拨打的电话号码以及接听、挂断等状态的变化,修改拨出的号码,加上一个IP拨号码,代码如下:
package com.rfstar.broadcasttest;
import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.telephony.TelephonyManager;import android.widget.Toast;public class CallReceiver extends BroadcastReceiver { boolean flag=false; @Override public void onReceive(Context context, Intent intent) { //判断是来电还是去电 if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){ //标识当前是拨出电话 flag=false; //获取当前号码 String phoneNumber=intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); Toast.makeText(context,"电话已拨出,号码为:"+phoneNumber,Toast.LENGTH_LONG).show(); //将拨出的号码改为代码12159的号码 setResultData("12159"+phoneNumber); }else{ //此时监控来电时状态 //获取电话服务管理器 TelephonyManager TelephonyManager telephonyManager=(TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE); switch (telephonyManager.getCallState()) { //电话处于响铃状态 case TelephonyManager.CALL_STATE_RINGING: //标识当前是来电 flag=true; //获取来电号码 String incomingPhoneNumber=intent.getStringExtra("incoming_number"); Toast.makeText(context,"来电号码:"+incomingPhoneNumber,Toast.LENGTH_LONG).show(); break; case TelephonyManager.CALL_STATE_OFFHOOK: if(flag){ Toast.makeText(context,"来电已被接通",Toast.LENGTH_LONG).show(); } break; case TelephonyManager.CALL_STATE_IDLE: if(flag){ Toast.makeText(context,"来电已被挂断",Toast.LENGTH_LONG).show(); } break; } } }}复制代码在onReceive()方法中,首先通过 intent.getAction()来判断是拨出电话还是外部来电。如果是拨出电话就获取拨出的号码,然后用 Toast展示此号码,并使用 setResultData()方法将此号码修改为带 IP 的号码进行拨号。如果是来电,就先通过 getSystemService()方法获取TelephonyManager 实例。这是一个系统服务类,专门用于管理通话。然后可以调用它的getSystemService()方法得到通话处于什么样状态,再根据不同的状态使用Toast展示不同的信息。
运行程序,按 home 键使当前程序进入后台,打开拨号界面,拨打电话,此时在界面上显示的号码就不再是拨出的号码,而是加上"12159"后的一个IP拨号号码。效果如下图所示。这里只展示了拨出电话时的效果。有关来电时的效果,大家可以使用上例自行测试验证。
![](https://static.assets-stash.eet-china.com/album/202112/07/130328m1mrjinuu0aubrmj.png)
android studio工具及手机模拟器以及更多工程源代码下载请前往微信公众号:大鸟科创空间,回复:android studio即可获取。
![](https://static.assets-stash.eet-china.com/album/202112/07/130513bfz5uffu2ehith58.jpg)
文章评论(0条评论)
登录后参与讨论