17.Android开发笔记:广播(一)

1.广播的分类

  • 标准广播
    所有广播接收器可同时收到

  • 有序广播
    一个时刻只能有一个广播接收器收到广播,且可决定可否截断

2.接收系统广播

Android内置了很多系统级的广播,比如:开机,电量变化,时间或时区

3.广播接收器

要想接收到广播,需要注册广播接收器,注册方式有两种:

  • 动态注册:代码注册

    • 主要是使用方法:registerReceiver(广播接收器,intentFilter)
  • 静态注册:AndroidMannifest.xml中注册

    • 主要代码
      <application>
         ....
         <receiver android:name=".MyBrodcastReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="com.example.mybroadcastDemo.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
      
      

如何创建广播接收器

  • 创建继承BroadcastReciever
  • 重写方法onRecieve

3.1 动态注册

示例:动态监听网络变化


public class MainActivity extends AppCompatActivity {

 private NetWorkChangeReciever netWorkChangeReciever;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);

     IntentFilter intentFilter = new IntentFilter();
     //当网络变化时系统发送该广播
     intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
     //注册广播接收器
     netWorkChangeReciever = new NetWorkChangeReciever();
     registerReceiver(netWorkChangeReciever, intentFilter);

 }

 @Override
 protected void onDestroy() {
     super.onDestroy();

     //注销广播接收器
     unregisterReceiver(netWorkChangeReciever);
 }

 class NetWorkChangeReciever extends BroadcastReceiver {

     @Override
     public void onReceive(Context context, Intent intent) {
         Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
         Log.d("network", "network changes");
        

     }
 }
}


关闭模拟器网络:

显示更详细的网络状态信息:

    class NetWorkChangeReciever extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
            Log.d("network", "network changes");

            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

            if (networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "网络不可用", Toast.LENGTH_SHORT).show();
            }
        }
    }

访问网络状态需要申请权限,在AndroidMannifest.xml文件中添加(Android Studio 有智能提示):

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

3.2 静态注册

静态注册广播被禁用:

解决安卓Android 8.0以上的静态广播无法注册

  • 1.创建接收器:右键本程序包节点->New Other->Broadcast Reciever, 命名为BootCompleteReciever

    • 勾选【Export】:表示广播接收器接收本程序以为的广播
    • 勾选【Enable】: 表示广播接收器可用
  • 2.BroadcastReceiver 修改 onReceive

public class BootCompleteReciever extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d("reciever", "this is boot complete reciever");
        Toast.makeText(context, "系统启动了", Toast.LENGTH_LONG).show();
    }
}  
  • 3.添加权限
    申请监听系统开机系统广播的权限,在AndroidMannifest.xml文件中添加
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcastdemo">
   ...
   <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    ...
  • 4.在AndroidMannifest.xml文件中
    receiver(BootCompleteReciever)的节点添加intent-filter标签: android.intent.action.BOOT_COMPLETED
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
       
        <receiver
            android:name=".BootCompleteReciever"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
        
         ...

注意:
不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,
当onReceive()方法运行了较长时间而没有结束时,程序就会报错。
因此广播接收器更多的是扮演一种打开程序其他组件的角色,比如
创建一条状态栏通知,或者启动一个服务等,

4.发送自定义广播

4.1 发送标准广播

使用方法`sendBroadcast(intent)`;
  • 定义广播接收器MyBrodcastReceiver:
public class MyBrodcastReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
     Toast.makeText(context, "收到自定义广播 ", Toast.LENGTH_LONG).show();
 }
}

  • AndroidMannifest.xml文件中注册广播接收器MyBrodcastReceiver
        <receiver android:name=".MyBrodcastReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="com.example.mybroadcastDemo.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

  • 发起自定义消息

    在MainActivity中的创建一个按钮,点击它发送指定义广播

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_send_my_broadcast"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="发送自定义广播 MY_BROADCAST"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

public class MainActivity extends AppCompatActivity {

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

        Button btn_send_my_broadcast = findViewById(R.id.btn_send_my_broadcast);
        btn_send_my_broadcast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.mybroadcastDemo.MY_BROADCAST");
                sendBroadcast(intent); //发送自定义标准广播
            }
        });
    }
}

点击按钮,接收程序内部自定义广播

  • 其它程序接收自定义广播com.example.mybroadcastDemo.MY_BROADCAST:
    创建一个新的工程:【MybroadcastReciever2】

    (1)创建广播接收器RecieveAntherAppBroadcast


public class RecieveAntherAppBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"mybroadcastreciever2:收到其它程序的广播(com.example.mybroadcastDemo.MY_BROADCAST)", Toast.LENGTH_SHORT).show();
    }
}

(2) 在AndroidMannifest.xml文件中注册广播接收器RecieveAntherAppBroadcast


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

  • 在程序【MyBrodcastReceiver】中点击按钮【发送自定义广播 MY_BROADCAST】,

    程序【MyBrodcastReceiver2】会受到广播:

4.2 发送有序广播

在项目【MyBrodcastReceiver】中

  • AndroidMannifest.xml文件中注册广播接收器MyBrodcastReceiver 的优先级:
    <intent-filter android:priority="100"
    数字越大,优先级越高

...

        <receiver android:name=".MyBrodcastReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter android:priority="100">
                <action android:name="com.example.mybroadcastDemo.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

...

  • 点击按钮时,使用有序广播
    sendOrderedBroadcast(intent, null);

       Button btn_send_my_broadcast = findViewById(R.id.btn_send_my_broadcast);
       btn_send_my_broadcast.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Intent intent = new Intent("com.example.mybroadcastDemo.MY_BROADCAST");
               //发起标准广播
               //sendBroadcast(intent);

               //发起有序广播,sendOrderedBroadcast()方法接收两个参数,
               // 第一个参数仍然是Intent,
               // 第二个参数是一个与权限相关的字符串,这里传入null就行
               sendOrderedBroadcast(intent, null);
           }
       });

  • 截断广播:

    广播接收器MyBrodcastReceiver使用 abortBroadcast(); 截断广播;


public class MyBrodcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "收到自定义广播 ", Toast.LENGTH_LONG).show();
        abortBroadcast(); //截断广播,优先级的广播器将无法收到广播
    }
}

这样项目【MyBrodcastReceiver2】的App将无法收到广播(com.example.mybroadcastDemo.MY_BROADCAST)。

5.本地广播

程序为了避免:
(1)广播被其它程序截获,
(2)其它程序不断地给程序发送垃圾广播
Android引入本地广播机制

本地广播主要就是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法
另外还有一点需要说明,本地广播是无法通过静态注册的方式来接收的。其实这也完全可以理解,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,
而发送本地广播时,我们的程序肯定是已经启动了,因此也完全不需要使用静态注册的功能。

创建一个新的项目【LocalBroadcastDemo】

  • 1.创建广播接收器LocalReceiver

public class LocalReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "本地广播", Toast.LENGTH_SHORT).show();
    }
}

  • 2.注册广播接收器
    localBroadcastManager.registerReceiver(localReceiver, intentFilter);

public class MainActivity extends AppCompatActivity {

    private LocalBroadcastManager localBroadcastManager;
    private LocalReceiver localReceiver;
    private final String localBrodcastName = "com.example.localbroadcastdemo.LOCAL_BROADCAST";

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

        localBroadcastManager = LocalBroadcastManager.getInstance(this);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(localBrodcastName);
        localReceiver = new LocalReceiver();
        //注册本地广播接收器
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);
     
       ...
    }
}

  • 3.发送本地广播

发送本地广播 localBroadcastManager.sendBroadcast(intent);


        Button btn_send_loacl_broadcast = findViewById(R.id.btn_send_loacl_broadcast);
        btn_send_loacl_broadcast.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(localBrodcastName);
                //发送本地广播
                localBroadcastManager.sendBroadcast(intent);
            }
        });

posted @ 2020-03-20 21:53  easy5  阅读(215)  评论(0编辑  收藏  举报