第一行代码第五章——详解广播机制

5.1 广播机制简介

Android中的广播主要分为两种类型:标准广播和有序广播。

标准广播

完全异步的在广播
在广播发出后,所有的广播接收器几乎在同一时刻接受到这条广播信息。

特点:广播效率高、没有任何先后顺序、无法被拦截

在这里插入图片描述

有序广播

同步执行的广播
广播发出后同一时刻,只会有一个BroadcastReceiver能够接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。
特点:广播接收器有先后顺序,优先级高的广播接收器先收到广播消息,可以被优先级高的广播接收器拦截。
在这里插入图片描述

5.2 接受系统广播

Android 内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到系统状态信息。
例如:
:开机广播
:电池电量发生变化广播
:时间或时区发生改变广播

广播接收器可以自由注册自己感兴趣的广播进行注册。注册的方式有两种:
● 代码中注册(也称为动态注册)
● AndroidManifest.xml中注册(也称为静态注册)

5.2.1 动态注册监听系统广播

动态注册系统广播步骤:
1.创建类继承BroadcastReceiver 重写onReceive()方法
2.通过 IntentFilter 类 注册或者取消注册广播

例如:动态注册广播监听时间变化

创建MyReceiver类继承BroadcastReceiver 重写onReceive()方法
在MainActivity里面通过IntentFilter 注册广播

MyReceiver 类

public class MyReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if ("android.intent.action.TIME_TICK".equals(action)) {
    
    
            Toast.makeText(context,"Timer",Toast.LENGTH_LONG).show();
        }
    }
}

MainActivity类

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
    
    private Button Time;
    private Button unTime;
    private IntentFilter intentFilter;
    private MyReceiver  myReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Time = findViewById(R.id.time);
        Time.setOnClickListener(this);
        unTime = findViewById(R.id.untime);
        unTime.setOnClickListener(this);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.TIME_TICK");
        myReceiver = new MyReceiver();
    }
    @Override
    public void onClick(View v) {
    
    
        switch (v.getId()) {
    
    
            case R.id.time:
                registerReceiver(myReceiver,intentFilter);
                break;
            case R.id.untime:
                unregisterReceiver(myReceiver);
                break;
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/time"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Reg Time">
    </Button>
    <Button
        android:id="@+id/untime"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="unReg Time">
    </Button>
</LinearLayout>

AndroidManifest.xml

    <application
       ....
        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
        </receiver>
       ...
  </application>

5.2.2 静态注册实现开机广播

静态广播可以在程序未启动的时候就能接收到广播。
步骤:
1.创建类继承BroadcastReceiver 重写onReceive()方法
2.在AndroidManifest.xml里面进行注册

隐式广播:是指那些没有具体发送给那个应用程序的广播,大多数系统广播属于隐式广播。但少数特殊的系统广播目前仍然允许使用静态方式来接受。

例如:静态注册接受开机广播,弹出Toast,

public class MyReceiver extends BroadcastReceiver {
    
    
    private static final String TAG = "Tim";
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if ("android.intent.action.BOOT_COMPLETED".equals(action)) {
    
    
            Toast.makeText(context,"Start",Toast.LENGTH_LONG).show();
            Intent intent1 = new Intent(context,MainActivity.class);
            intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent1);
            Log.d(TAG," ----------start----------");
        }
}

注意:intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 加上才可以启动应用程序。
AndroidManifest.xml加上权限,action

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
       
        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

5.3 自定义广播

广播主要分为标准广播和有序广播,下面分别来实践下具体实现。

隐式广播:是指那些没有具体发送给那个应用程序的广播,大多数系统广播属于隐式广播。但少数特殊的系统广播目前仍然允许使用静态方式来接受。

5.3.1 发送标准广播

发送隐式广播(action):接受方必须动态接受(action)。
发送定向广播(action,packageName):接受方可以静态接受。

例如:

发送隐式广播:

发送方:

Intent intent = new Intent();
intent.setAction("my_receiver");
sendBroadcast(intent); //发送隐式广播

接受方:AndroidMainfest.xml不用进行注册

private  IntentFilter intentFilter;
private MyReceiver myReceiver;
intentFilter = new IntentFilter();
intentFilter.addAction("my_receiver");
myReceiver = new MyReceiver();
registerReceiver(myReceiver,intentFilter); //注册隐式广播

unregisterReceiver(myReceiver);   //取消注册隐式广播
public class MyReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if ("my_receiver".equals(action)) {
    
    
            Toast.makeText(context,"my_receiver",Toast.LENGTH_LONG).show();
        }else  if ("my_receiver1".equals(action)) {
    
    
            Toast.makeText(context,"<<<<<<<>>>>>",Toast.LENGTH_LONG).show();
        }
    }
}

发送定向广播:

发送方:设置action 和接受方的packagename

Intent intent = new Intent();
intent.setPackage(getPackageName());
intent.setAction("my_receiver1");
sendBroadcast(intent);

接受方:
AndroidManifest.xml

        <receiver
            android:name=".MyReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="my_receiver1"/>
            </intent-filter>
        </receiver>
public class MyReceiver extends BroadcastReceiver {
    
    
    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        String action = intent.getAction();
        if ("my_receiver".equals(action)) {
    
    
            Toast.makeText(context,"my_receiver",Toast.LENGTH_LONG).show();
        }
    }
}

5.3.2 发送有序广播

发送有序广播的步骤跟上面发送标准广播的步骤一样,只是调用的方法不一样。
有序广播

发送方

sendOrderedBroadcast(intent,null)方法发送有序广播

参数一:intent的对象
参数二:与权限相关的字符串,一般传入null就行

接受方
接受方可以设置广播接受的优先级,也可以截断广播,使广播不在向下传递。

1.设置优先级:
android:priority=“1000” 优先级
这个属性只对activity 和 receivers 是有意义的。
priority 必须是整数,默认是0 , 范围是[-1000, 1000]
AndroidMainfest.xml

  <receiver
      android:name=".MyBroadcastReceiver"
      android:enabled="true"
      android:exported="true">
      <intent-filter android:priority="1000">
          <action android:name="com.example.broadcasttest.MY_BROADCASTT"/>
      </intent-filter>
  </receiver>

2.在MyBroadcastReceiver类中可以设置广播,被截断
abortBroadcast();

    @Override
    public void onReceive(Context context, Intent intent) {
    
    
      String action = intent.getAction();
      if ("order".equals(action)) {
    
    
          Toast.makeText(context,"order",Toast.LENGTH_LONG).show();
          abortBroadcast();
      }
    }

5.4 使用本地广播

为了解决广播安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接受来自本应用程序发出的广播。
本地广播使用LocalBroadcastManager,来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
本地广播不在AndroidMainfest.xml里面进行注册,在代码里面注册
因为静态注册主要是在程序为启动时接受,本地广播主要在本apk内部进行传递。

发送

LocalBroadcastManager mLocalBroadcastManager;
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);

Intent intent = new Intent();
intent.setAction("Local");
intent.putExtra("send","hello local broadcast");
mLocalBroadcastManager.sendBroadcast(intent);

接受

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("Local");
LocalRecv localRecv = new LocalRecv();
mLocalBroadcastManager.registerReceiver(localRecv,intentFilter);

class  LocalRecv extends BroadcastReceiver {
    
    
      @Override
       public void onReceive(Context context, Intent intent) {
    
    
           String action = intent.getAction();
           if ("Local".equals(action)) {
    
    
                String string = intent.getStringExtra("send");
                Toast.makeText(context,string,Toast.LENGTH_LONG).show();
           }
        }
    }

本地广播的优势

发送的广播不会离开自己的程序,所以数据不会泄露
其它程序无法将广播发送到我们程序的内部,所以不会有安全漏洞隐患
发送本地广播比发送系统全局广播更加高效

小项目:强制下线功能实现。

猜你喜欢

转载自blog.csdn.net/weixin_41477306/article/details/105593333