全局大喇叭--广播机制


为了便于进行系统级别的消息通知,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();
        }
    }
}

(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();
    }
}

(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>

(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);
            }
        });

在这里插入图片描述

2. 发送有序广播

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

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

(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) 回到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,第二个则是与权限相关的字符串
            }
        });

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

abortBroadcast();

能看到自由一条消息传播,经过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. 新建一个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();
            }
        }
    }
}

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);
    }
}

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>

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();
                }
            }
        });
    }
}

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

<Button
    android:id="@+id/force_offline"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Send force _______________"/>

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);
            }
        });
    }
}

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();
        }
    }
}

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>

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值