您的位置:首页 > 其它

详解广播机制——初识

2018-02-24 13:58 225 查看
总结自郭神的《第一行代码》

Android中的广播类型

Android中的广播主要可以分为两种类型,标准广播和有序广播

标准广播(Normal broadcasts)

是一种完全异步执行的广播,在广播发出之后,所有的 广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可 言。这种广播的效率会比较高,但同时也意味着它是无法被截断的



有序广播(Orderedbroadcasts)

则是一种同步执行的广播,在广播发出之后,同一时刻 只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广 播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先 收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器 就无法收到广播消息了



接收系统广播

Android内置了很多系统级别的广播,我们可以在应用程序中通过监听这些广播来得到 各种系统的状态信息。比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一 条广播,时间或时区发生改变也会发出一条广播等等。如果想要接收到这些广播,就需要使 用广播接收器,下面我们就来看一下它的具体用法

动态注册监听网络变化

广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广 播接收器就能够收到该广播,并在内部处理相应的逻辑

注册广播的方式一般有两种,在代 码中注册和在 AndroidManifest.xml中注册,其中前者也被称为动态注册,后者也被称为静态 注册

那么该如何创建一个广播接收器呢?

其实只需要新建一个类,让它继承自BroadcastReceiver, 并重写父类的 onReceive()方法就行了

这样当有广播到来时,onReceive()方法就会得到执行, 具体的逻辑就可以在这个方法中处理

栗子:网络变化时提示

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bu
4000
ndle;
import android.widget.Toast;

public class Test extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);

intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver,intentFilter);
}

class NetworkChangeReceiver extends BroadcastReceiver{

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

@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
}


运行结果:当网络发生变化时,提示信息

对代码的解释

我们在 MainActivity 中定义了一个内部类 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()方法来实现的

栗子优化

不过只是提醒网络发生了变化还不够人性化,最好是能准确地告诉用户当前是有网络还 是没有网络,因此我们还需要对上面的代码进行进一步的优化

class NetworkChangeReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.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();
}
}


这里查询系统的网络状态就是需要声明权限的。打开 AndroidManifest.xml文件,在里面加入如下权限就可以查询系统网络状态了

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


运行结果:打开网络,提示network is available,关闭网络提示network is unavailable

对代码的解释

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

静态注册实现开机启动

动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是 它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate()方法中的。那么有没有什么办法可以让程序在未启动的情况下就能接收到广播 呢?这就需要使用静态注册的方式了

这里我们准备让程序接收一条开机广播,当收到这条广播时就可以在 onReceive()方法里 执行相应的逻辑,从而实现开机启动的功能

栗子

新建一个 BootCompleteReceiver 继承自 BroadcastReceiver

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

public class BootCompleteReceiver extends BroadcastReceiver {

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


AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xx.yy">

<uses-permission android:name="android.permission.RECEIVE_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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

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

</manifest>


对代码的解释

AndroidManifest.xml的标签内出现了一个新的标签,所有静态注册的广播接收器 都是在这里进行注册的。它的用法其实和标签非常相似,首先通过 android:name 来指定具体注册哪一个广播接收器,然后在标签里加入想要接收的广播就行了, 由于Android系统启动完成后会发出一条值为android.intent.action.BOOT_COMPLETED的广 播,因此我们在这里添加了相应的 action

监听系统开机广播也是需要声明权限的,可以看到,我们使用 标签又加入了一条 android.permission.RECEIVE_BOOT_COMPLETED权限

【注意】

要测试效果,需要重启模拟机,所以,当我们把模拟机关掉后,但是不要直接点运行!!,要打开AVD



然后选择你要启动的模拟机才可以看到效果



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: