安卓开发之广播机制

1.广播机制简介

  • 标准广播(normal broadcasts):完全异步执行,广播发出后,所有的广播接收器都会在同一时刻接收到这条广播消息
  • 有序广播 (ordered broadcasts):同步执行,同一时刻只有一个广播接收器收到,当执行完后再继续传递。优先级高的广播接收器可以先收到消息,还可以截断广播接收器。

2.接收系统广播

动态注册监听网络变化

在代码中注册称为动态注册,在AndroidManifest.xml注册称为静态注册。

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.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        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();
            }
        }
    }
}
  • 定义了一个内部类NetworkChangeReceiver ,这个类是继承自BroadcastReceiver 的,并重写了父类的onReceive() 方法。这样每当网络状态发生变化时,onReceive() 方法就会得到执行,这里只是简单地使用Toast提示了一段文本信息

  • 观察onCreate() 方法,首先我们创建了一个IntentFilter 的实例,并给它添加了一个值为android.net.conn.CONNECTIVITY_CHANGE 的action,为什么要添加这个值呢?因为当网络状态发生变化时,系统发出的正是一条值为android.net.conn.CONNECTIVITY_CHANGE 的广播,也就是说我们的广播接收器想要监听什么广播,就在这里添加相应的action

  • 接下来创建了一个NetworkChangeReceiver 的实例,然后调用registerReceiver() 方法进行注册,将NetworkChangeReceiver 的实例和IntentFilter 的实例都传了进去,这样NetworkChangeReceiver 就会收到所有值为android.net.conn.CONNECTIVITY_CHANGE 的广播,也就实现了监听网络变化的功能。

  • 动态注册的广播接收器一定都要取消注册才行,这里我们是在onDestroy() 方法中通过调用unregisterReceiver() 方法来实现的

  • 在onReceive() 方法中,首先通过getSystemService() 方法得到了ConnectivityManager 的实例,这是一个系统服务类,专门用于管理网络连接的。然后调用它的getActiveNetworkInfo() 方法可以得到NetworkInfo 的实例,接着调用NetworkInfo 的isAvailable() 方法,就可以判断出当前是否有网络了,最后我们还是通过Toast的方式对用户进行提示

  • 如果程序需要进行一些对用户来说比较敏感的操作,就必须在配置文件中声明权限才可以,否则程序将会直接崩溃。比如这里访问系统的网络状态就是需要声明权限的。打开AndroidManifest.xml文件

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.broadcasttest">
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        ...
    </manifest>
    

静态注册实现开机启动

1.可以使用Android Studio提供的快捷方式来创建一个广播接收器,右击com.example.broadcasttest包→New→Other→Broadcast Receiver

2.修改BootCompleteReceiver中的代码

public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
    }
}

3.静态的广播接收器一定要在AndroidManifest.xml文件中注册才可以使用, 标签内出现了一个新的标签,目前BootCompleteReceiver还是不能接收到开机广播的。Android系统启动完成后会发出一条值为android.intent.action.BOOT_COMPLETED的广播,因此我们在 标签里添加了相应的action。另外,监听系统开机广播也是需要声明权限的,可以看到,我们使用 标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED 权限。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

3.发送自定义广播

发送标准广播

1.发送广播之前,我们还是需要先定义一个广播接收器来准备接收此广播才行,不然发出去也是白发。因此新建一个MyBroadcastReceiver

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_
            SHORT).show();
    }
}

2.AndroidManifest.xml中对这个广播接收器进行修改

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest">
    ...
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

3.这里让MyBroadcastReceiver接收一条值为com.example.broadcasttest.MY_BROADCAST 的广播,因此待会儿在发送广播的时候,我们就需要发出这样的一条广播。接下来修改activity_main.xml中的代码

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Broadcast"
        />
</LinearLayout>

4.在布局文件中定义了一个按钮,用于作为发送广播的触发点。然后修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {
    ...
    @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);
            }
        });
        ...
    }
    ...
}

发送有序广播

将标准广播改成有序广播只需要

  • @Override
    public void onClick(View v) {
        Intent intent = new Intent("com.example.firstdemo.MY_BROADCAST");
        sendBroadcast(intent);
    }
    

    改成

    @Override
    public void onClick(View v) {
        Intent intent = new Intent("com.example.firstdemo.MY_BROADCAST");
        sendOrderedBroadcast(intent,null);
    }
    
  • 还可以设置优先级

    <intent-filter android:priority="100">
                    <action android:name="com.example.broadcasttest.MY_BROADCAST" />
    </intent-filter>
    
  • 还可以设置截断

    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received in MyBroadcastReceiver",
                Toast.LENGTH_SHORT).show();
            abortBroadcast();
        }
    }
    
上一篇:鸿蒙MVP DEMO(含线程切换及Toast封装)


下一篇:Android常用设置