Android的四大组件——BroadCast(广播)

1.Broadcast简介

Broadcast是android中的四大组件之一,是在组件之间传播数据(Intent)的一种机制。广播的发送者和接收者事先是不需要知道对方的存在的。这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。

广播具有以下特性:

1.广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁 2.广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框 3.最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉 4.耗时的较长的工作最好放在服务中完成广播接收器

2.广播接收器

广播接收器主要分为两种类型:标准广播有序广播

2.1标准广播

标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播的信息,因此他们之间没有任何的先后顺序可言。传播如下图所示。

标准广播又区分为两种:动态注册静态注册

2.1.1静态广播注册

MyStaticReceiver这个类里面很简单,只做了打印收到的信息:

package com.hope.demo.broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

import com.hxc.supreme.utils.ToastUtil;

public class MyStaticReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("MyStaticReceiver", "onReceive: "+intent.getStringExtra("info"));
    }
}

 Manifeast中的代码块:

<receiver
       android:name=".broadcast.MyStaticReceiver"
       android:enabled="true"
       android:exported="true">
       <intent-filter>
            <action android:name="hopu"/>
       </intent-filter>
</receiver>

然后就是主界面一个点击按钮,布局文件很简单:

public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tvStaticBroadcast;
    private TextView tvDynamicBroadcast;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
        tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
        tvStaticBroadcast.setOnClickListener(this);
        tvDynamicBroadcast.setOnClickListener(this);
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv_static_broadcast:
                sendBroadcast();
                break;
            case R.id.tv_dynamic_broadcast:
                break;
        }
    }

    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }


}

然后看一下logcat中的日志输出:

02-15 15:33:14.300 15384-15384/com.hxc.supreme I/MyStaticReceiver: onReceive: 这是一条静态广播

然而,在Android8.0及以上的系统中,收不到静态广播!Google了一下发现,谷歌在8.0后为了提高效率,删除了静态注册,防止关闭App后广播还在, 造成内存泄漏, 现在静态注册的广播需要指定包名!!!

意思就是在8.0以后Google官方推荐用动态注册替换静态注册,那我们就指定一下包名看看是否管用:

代码只改动了发送广播的方法:

private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());//Android8.0以上需指定包名
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }

看下logcat的输出日志:

02-15 15:46:21.891 11181-11181/com.hxc.supreme I/MyStaticReceiver: onReceive: 这是一条静态广播

事实是证明可以的,但是Google推荐使用动态注册,那我么接下来就看一下动态注册的使用方式。

2.1.2动态广播注册

直接上代码

public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView tvStaticBroadcast;
    private TextView tvDynamicBroadcast;
    private DynamicReceiver dynamicReceiver;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast);
        tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
        tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
        tvStaticBroadcast.setOnClickListener(this);
        tvDynamicBroadcast.setOnClickListener(this);
        dynamicReceiver = new DynamicReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("husanity");
        registerReceiver(dynamicReceiver, intentFilter);
    }


    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.tv_static_broadcast:
                sendBroadcast();
                break;
            case R.id.tv_dynamic_broadcast:
                sendDynamicBroadcast();
                break;
        }
    }

    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());//Android8.0以上需指定包名
        intent.setAction("hopu");
        intent.putExtra("info", "这是一条静态广播");
        sendBroadcast(intent);
    }

    private void sendDynamicBroadcast() {
        Intent intent = new Intent();
        intent.setAction("hopu");
        intent.putExtra("extra", "这是一条动态广播");
        sendBroadcast(intent);

    }

    class DynamicReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("BroadcastActivity", "onReceive: " + intent.getStringExtra("extra"));

        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //onDestroy中需要反注册,用来优化内存空间避免内存泄漏
        unregisterReceiver(dynamicReceiver);
    }
}

看下logcat打印日志:

02-15 16:08:25.559 11597-11597/com.hopu.demo I/BroadcastActivity: onReceive: 这是一条动态广播

2.2.4具体案例

动态注册广播接收者,接收网络发生变法的广播

public class HomeActivity extends AppCompatActivity {

    private NetWorkReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        //创建一个意图过滤器
        IntentFilter filter = new IntentFilter();
        //接收网络改变的action
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);

        receiver = new NetWorkReceiver();
		//注册广播
        this.registerReceiver(this.receiver, filter);
    }

    /*
    * 取消注册
    * */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.unregisterReceiver(this.receiver);
    }

    public class NetWorkReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

            //如果当前有默认的网络就返回NetworkInfo 否则就返回 null
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            //因为可能是null 所以要先判断是否为空
            if (networkInfo != null && networkInfo.isAvailable()) {
                if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                    Toast.makeText(context, "Wifi", Toast.LENGTH_SHORT).show();

                } else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                    Toast.makeText(context, "流量", Toast.LENGTH_SHORT).show();
                }
            } else {
                Toast.makeText(context, "世界上最遥远的距离就是没有网", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

静态注册广播接收者,实现开机启动

<!--注册我们的开机广播-->
<receiver
	android:name=".MyBootComplatedReceiver"
	android:enabled="true"
	android:exported="true">
	<intent-filter>
		<action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
public class MyBootComplatedReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent gotoIntent = new Intent(context, RootComplatedActivity.class);
        context.startActivity(gotoIntent);
    }
}

2.2有序广播

有序广播:

通过Context.sendOrderedBroadcast来发送,所有的receiver依次执行。BroadcastReceiver可以使用setResult系列函数来结果传给下一个BroadcastReceiver,通过getResult系列函数来取得上个BroadcastReceiver返回的结果,并可以abort系列函数来让系统丢弃该广播,使用该广播不再传送到别的BroadcastReceiver。可以通过在intent-filter中设置android:priority属性来设置receiver的优先级,优先级相同的receiver其执行顺序不确定。

举例:

短信拦截:你可以设置自己的app的广播接收器的级别高于系统原来的级别,并且收到后中断往下传播,这样的话收件箱里面就不会收到短信了。

猜你喜欢

转载自blog.csdn.net/weixin_53431933/article/details/125951688