• 全局大喇叭--广播机制



    为了便于进行系统级别的消息通知,Android也引入了一套类似的广播消息机制。

    一、 广播机制简介

    广播的类型:标准广播和有序广播

    (1) 标准广播(Normal broadcasts)

    是一种完全异步执行的广播,在广播发出后,所有的广播接收器几乎会在同一时刻接收到这条广播信息,因此他们之间没有先后顺序。这种广播的效率比较高,但同时意味着无法被截断的。
    在这里插入图片描述

    (2) 有序广播(Ordered broadcasts)

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

    二、 接收系统广播

    Android内置了很多系统级别的广播,在应用程序中通过监听这些广播来得到各种系统的状态信息。(手机开机完成后、电池的电量变化、会发出一条广播)。如果想要接收这些广播,就需要使用广播接收器。

    1. 动态注册监听网络变化

    广播接收器可以自由地对自己感兴趣的广播进行注册,一般有两种::在代码中注册(动态注册)和在AndroidMainfest.xml中注册(静态注册)。
    如何创建一个广播接收器呢?
    首先需要新建一个类,让他继承自BroadcastReceiver,并重写父类的onReceive()的方法就行了。
    (1) 新建一个BroadcastTest项目,修改MainActivity中的代码。

    public class MainActivity extends AppCompatActivity {
    
        private IntentFilter intentFilter;
        private NetworkChangeReceiver networkChangeReceiver;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            intentFilter =new IntentFilter();//创建IntentFilter的实例
            intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//广播想要监听的内容,添加相应的action
            networkChangeReceiver =new NetworkChangeReceiver();//创建 NetworkChangeReceiver实例
            registerReceiver(networkChangeReceiver,intentFilter);//这样就会接收到广播,实现了监听网络变化功能
        }
        @Override
        protected void onDestroy() { //动态注册的广播接收器一定都要取消注册才行
            super.onDestroy();
            unregisterReceiver(networkChangeReceiver);
        }
        //每当网络状态发生变化时,onReceive()得到执行,只是简单地使用Toast提示一段文本信息
        class NetworkChangeReceiver extends BroadcastReceiver{
            @Override
            public void onReceive(Context context, Intent intent) {
                Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    • 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

    (2) 运行程序,会出现一条广播。接着按下home键(不能按back键,否则onDestroy()方法会执行),然后打开setting程序 ->Data usage进入到数据使用详情界面,然后开关Cellular data 按钮来开启和禁用网络,你会看到Toast提醒网络发生变化。
    在这里插入图片描述

    2. 静态注册实现开机启动

    让程序在未启动的情况下就能接收到广播—静态注册

    1. 可以使用AS提供的快捷方式来创建一个广播接收器,点击com.example.broadcaasttest 包新建…,会弹出一个窗口。
      在这里插入图片描述

    2. 将广播接收器命名为如图所示,Exported属性表示是否允许这个广播接收器接收本程序以外的广播;Enabled属性表示是否启用这个广播接收器。
      在这里插入图片描述
      (3) 修改其中代码,如图所示,用onReceive()方法中使用Toast弹出一段提示信息
      在这里插入图片描述
      (4) 静态广播接收器一定要在AndroidManifest.xml文件中注册才可以使用,不过AS已经自动完成了,给他添加标签加入action,并添加权限
      在这里插入图片描述
      在这里插入图片描述

    (5) 重新运行程序后,就可以接收开机广播了。
    在这里插入图片描述

    三、 发送自定义广播

    1. 发送标准广播

    (1) 首先新建一个MyBroadcastReceiver

    public class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "recevied in MyBraodcastReceiver ", Toast.LENGTH_SHORT).show();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2) 然后在AndroidMainfest.xml中对这个广播接收器进行修改,让接收器接收到com.example.broadcasttest.MY_BROADCAST的广播

      <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (3) 在布局中定义一个按钮,用于发送广播的触发点。

            Button button =(Button)findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent =new Intent("com.example.broadcasttest.MY_BROADCAST");
                    sendBroadcast(intent);
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    2. 发送有序广播

    (1) 新建一个项目,创建AntherBroadcastReceiver,代码如下:

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received anothorReceiver~~~~~", Toast.LENGTH_SHORT).show();
    }
    
    • 1
    • 2
    • 3
    • 4

    (2) 对AndroidMainifest.xml对这个广播接收器进行修改,到这里,程序发出的还是标准广播,让我们尝试一下发送有序广播。

     <receiver
                android:name=".AnthorReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    在这里插入图片描述
    (1) 回到BroadcastTest项目,修改MainActivity中代码

       Button button =(Button)findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent =new Intent("com.example.broadcasttest.MY_BROADCAST");
                  //  sendBroadcast(intent);
                    sendOrderedBroadcast(intent,null); //第一个参数是intent,第二个则是与权限相关的字符串
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (2) 修改AndroidMainifest.xml中的代码,用priority设置优先级
    在这里插入图片描述
    (3) 修改MyBroadcastReceiver中的代码

    abortBroadcast();
    
    • 1

    能看到自由一条消息传播,经过abortBroadcast()方法,就表示将这条广播截断

    四、 使用本地广播

    为了解决广播的安全性问题,使用这个机制只能在应用程序的内部进行传递。修改MainActivity中的代码

    public class MainActivity extends AppCompatActivity {
    
        private IntentFilter intentFilter;
        private  LocalReceiver  localReceiver;
        private  LocalBroadcastManager localBroadcastManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            localBroadcastManager =LocalBroadcastManager.getInstance(this);
            Button button =(Button)findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent =new Intent("com.example.broadcasttest.MY_BROADCAST");
                  //  sendBroadcast(intent);
                  //  sendOrderedBroadcast(intent,null);
                    localBroadcastManager.sendBroadcast(intent);
                }
            });
            intentFilter =new IntentFilter();//创建IntentFilter的实例
            intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//广播想要监听的内容,添加相应的action
            localReceiver =new LocalReceiver();
            localBroadcastManager.registerReceiver(localReceiver,intentFilter);//注册本地广播监听器
        }
        @Override
        protected void onDestroy() {
            super.onDestroy();
            localBroadcastManager.unregisterReceiver(localReceiver);
        }
        class LocalReceiver extends BroadcastReceiver{
            @Override
            public void onReceive(Context context, Intent intent) {
                Toast.makeText(context, "received++++++++++++++", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    • 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. 新建一个BroadcastBestPractice项目,创建ActivityCollector类,用于管理所有活动,代码下所示

    public class ActivityCollector {
        public static List<Activity> activities =new ArrayList<>();
        public static void  addActivity(Activity activity){
            activities.add(activity);
        }
        public static void removeActivity(Activity activity){
            activities.remove(activity);
        }
        public static void finishAll(){
            for (Activity activity :activities){
                if (!activity.isFinishing()){
                    activity.finish();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2. 创建BaseActivity类作为所有活动的父类

    public class BaseActivity extends AppCompatActivity {
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityCollector.addActivity(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3. 然后创建一个登陆界面的活动,新建LoginActivity,并生成相应的布局文件,编辑login.xml文件,有登陆账号和密码进行登陆。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".LoginActivity">
    
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="60dp">
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:textSize="18sp"
                android:text="Account:"/>
            <EditText
                android:id="@+id/account"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center_vertical"/>
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="60dp">
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:gravity="center_vertical"
                android:textSize="18sp"
                android:text="Password:"/>
            <EditText
                android:id="@+id/password"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center_vertical"
                android:inputType="textPassword"/>
        </LinearLayout>
        <Button
            android:id="@+id/login"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="Login"/>
    </LinearLayout>
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    4. 修改LoginActivity中的代码是简单的登陆功能,如果登陆成功则进入MainActivity中。

    public class LoginActivity extends BaseActivity {
    
        private EditText accountEdit;
        private EditText passwordEdit;
        private Button login;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            accountEdit =(EditText) findViewById(R.id.account);
            passwordEdit =(EditText) findViewById(R.id.password);
            login=(Button) findViewById(R.id.login);
            login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String account =accountEdit.getText().toString();
                    String password =passwordEdit.getText().toString();
                    if (account.equals("admin")&&password.equals("123")){
                        Intent intent =new Intent(LoginActivity.this,MainActivity.class);
                        startActivity(intent);
                        finish();
                    }else {
                        Toast.makeText(LoginActivity.this, "try again ", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
    
    • 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

    5. 在main.xml中增加一个按钮,点击按钮则显示强制退出

    <Button
        android:id="@+id/force_offline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send force _______________"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6. 修改MainActivity代码,用于通知广播,强制下线

    public class MainActivity extends BaseActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button forceOffline=(Button) findViewById(R.id.force_offline);
            forceOffline.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");
                    sendBroadcast(intent);
                }
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7. 这些活动都继承BaseActivity

    public class BaseActivity extends AppCompatActivity {
    
        private ForceofflineReceiver receiver;
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityCollector.addActivity(this);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (receiver!=null){
                unregisterReceiver(receiver);
                receiver=null;
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            IntentFilter intentFilter =new IntentFilter();
            intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
            receiver =new ForceofflineReceiver();
            registerReceiver(receiver,intentFilter);
        }
        class ForceofflineReceiver extends BroadcastReceiver{
            @Override
            public void onReceive(final Context context, Intent intent) {
                AlertDialog.Builder builder =new AlertDialog.Builder(context);
                builder.setTitle("Warning!!!!!!!");
                builder.setMessage("TRY AGAIN!!!!!!!!!!!");
                builder.setCancelable(false);
                builder.setPositiveButton("ok==", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCollector.finishAll(); //销毁所有活动
                        Intent intent =new Intent(context,LoginActivity.class);
                        context.startActivity(intent);
                    }
                });
                builder.show();
            }
        }
    }
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    8. 在AndroidMainfest.xml文件进行修改,启动手机时进入登陆页面

     <activity
            android:name=".LoginActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述
    点击按钮,强制下线
    在这里插入图片描述

  • 相关阅读:
    【springboot】自动整合Tomcat原理
    vue3中$refs使用调整
    R语言和医学统计学(4):秩和检验
    基于Python开发的飞机大战小游戏彩色版(源码+可执行程序exe文件+程序配置说明书+程序使用说明书)
    HTML期末作业课程设计期末大作业--小米网站开发者平台首页 1页
    体系结构评估——(二)体系结构决策及架构评估方法
    网络:IP与MAC
    Vue14 深度监视
    如何退出或卸载奇安信天擎软件
    最新java基础部分面试题大全
  • 原文地址:https://blog.csdn.net/qq_48019875/article/details/126218159