Android广播机制原理与开发

 更新时间:2023年02月23日 09:08:43   作者:Godams  
Android广播机制就是在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理

广播机制简介

  • 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)
  • 有序广播:同步执行,广播发出后同一时刻只会有一个广播接收器能收到这条广播消息,前面的接收器可以截断正在传递的广播

接收系统广播

广播接收器可在代码中注册和AndroidManifest.xml中注册,前者为动态注册,后者被称为静态注册。

动态注册监听网络变化

示例代码:

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.addAction("android.net.conn.CONNECTIVITY_VHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
            }
            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
        }
    }
}

静态注册实现开机启动

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

Export属性表示是否允许这个广播接收器接收本程序以外的广播,enable表示是否使用这个广播接收器。

<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

添加了filter就可以过滤了

可以通过左键新建-》其它来新建静态注册广播

广播接收器中不允许开线程,当onReceive方法运行较长时间而没结束时,程序就会报错,所以其中不能添加过多的逻辑或任何耗时操作。

发送自定义广播

发送标准广播

@Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        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);
            }
        });
    }

通过点击按钮发送广播

public class myBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
    }
}

这里是自定义的接收器

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

在xml中定义过滤的广播类型

发送有序广播

广播是一种跨进程的通信方式

protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        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");
                sendOrderedBroadcast(intent, null);
            }
        });
    }

只需要修改一行代码 sendOrederedBroadcast即可发送有序广播,同时在接收器的xml文件中可以设置优先级

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
<!--            在这里设置优先级-->
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

如果想要在接收到广播之后就让广播停止继续传递呢,修改onReceive的代码即可

public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
//        停止继续传递
        abortBroadcast();
    }

使用本地广播

前面我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。

使用本地广播则发出的广播只能在应用程序内部传递,并且接收器也只能接收来自本应用程序发出的广播。

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManger;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        localBroadcastManger = LocalBroadcastManager.getInstance(this); //获取实例
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManger.sendBroadcast(intent); //发送本地广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManger.registerReceiver(localReceiver, intentFilter); //注册本地广播监听器
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        localBroadcastManger.unregisterReceiver(localReceiver);
    }
    class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent){
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

代码的不同主要在于需要首先获取实例,然后还要有注册。

需要注意的是,本地广播无法通过静态注册来接收。

使用广播实现强制下线功能

强制下线功能首先需要实现下关闭所有的活动的功能,新建一个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();
            }
        }
    }
}

然后创建baseActivity类作为活动的父类,代码如下:

public class BaseActivity extends AppCompatActivity {
    private ForceOfflineReceiver receiver;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }
    @Override
    protected void onResume(){
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
        receiver = new ForceOfflineReceiver();
        registerReceiver(receiver, intentFilter);
    }
    @Override
    protected void onPause(){
        super.onPause();
        if(receiver != null){
            unregisterReceiver(receiver);
            receiver = null;
        }
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
    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("You are forced to be offline");
            builder.setCancelable(false);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int which) {
                    ActivityCollector.finishAll(); //销毁所有活动
                    Intent intent = new Intent(context, LoginActivity.class);
                    context.startActivity(intent); //重新启动loginActivity
                }
            });
            builder.show();
        }
    }
}

我们可以注意到,之前编写注册和销毁接收器的时候是在onCreate和onDestroy这两个函数里的,但是上面代码中却写在了onResume和onPause里面,这是因为我们每次都只需要在栈顶的活动接收广播,非栈顶活动没必要接收这条广播。

除此之外,我们创建一个登陆的活动,在活动页面上放置输入框,并编写登录逻辑

<?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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".ui.login.LoginActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="Account:"/>
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/account"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="password:"/>
        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/password"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>
    <Button
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:id="@+id/login"
        android:text="Login"
        tools:ignore="MissingConstraints"></Button>
</androidx.constraintlayout.widget.ConstraintLayout>
public class LoginActivity extends AppCompatActivity {
    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();
                //如果账号是admin 且密码是123456则登录成功
                if(account.equals("admin") && password.equals("123456")){
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                }else {
                    Toast.makeText(LoginActivity.this, "account is invalid", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

这样就模拟了登录的窗口,然后在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.FROCE_OFFLINE");
                sendBroadcast(intent);
            }
        });
    }
}

这样逻辑就差不多了,下面去AndroidManifest.xml中修改下程序入口即可:

到此这篇关于Android广播机制原理与开发的文章就介绍到这了,更多相关Android广播机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android工具类ImgUtil选择相机和系统相册

    Android工具类ImgUtil选择相机和系统相册

    这篇文章主要为大家详细介绍了Android工具类ImgUtil选择相机和系统相册,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-10-10
  • Android最简单的状态切换布局实现教程

    Android最简单的状态切换布局实现教程

    这篇文章主要给大家介绍了关于Android中最简单的状态切换布局的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-10-10
  • Android 优化之卡顿优化的实现

    Android 优化之卡顿优化的实现

    这篇文章主要介绍了Android 优化之卡顿优化的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Android自定义View仿腾讯TIM下拉刷新View

    Android自定义View仿腾讯TIM下拉刷新View

    这篇文章主要给大家介绍了关于Android自定义View仿腾讯TIM下拉刷新View的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • WebView的介绍与简单实现Android和H5互调的方法

    WebView的介绍与简单实现Android和H5互调的方法

    这篇文章主要给大家介绍了关于WebView与简单实现Android和H5互调的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-05-05
  • 仿墨迹天气在Android App中实现自定义zip皮肤更换

    仿墨迹天气在Android App中实现自定义zip皮肤更换

    这篇文章主要介绍了仿墨迹天气在Android App中实现自定义zip皮肤更换的方法,即让用户可以自行通过自制或者下载的zip皮肤包进行换肤,需要的朋友可以参考下
    2016-02-02
  • Android 有效的解决内存泄漏的问题实例详解

    Android 有效的解决内存泄漏的问题实例详解

    这篇文章主要介绍了Android 有效的解决内存泄漏的问题的相关资料,这里举例说明,如何实现解决内存泄漏,需要的朋友可以参考下
    2016-11-11
  • Android使用NestedScrollView 内嵌RecycleView滑动冲突问题解决

    Android使用NestedScrollView 内嵌RecycleView滑动冲突问题解决

    这篇文章主要介绍了Android使用NestedScrollView 内嵌RecycleView滑动冲突问题解决,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2022-06-06
  • Android自定义View实现圆弧进度效果逐步完成过程

    Android自定义View实现圆弧进度效果逐步完成过程

    在Android开发中,通过自定义View实现自己想要的效果是作为android开发程序员的一项必备技能,自定义View对于android开发来说也是比较难的一项技术
    2023-04-04
  • 基于RxJava框架实现获取验证码的辅助类

    基于RxJava框架实现获取验证码的辅助类

    这篇文章主要为大家详细介绍了基于RxJava框架实现获取验证码的辅助类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-06-06

最新评论