Android BroadcastReceiver机制的详解

Android广播机制的详解

工作也一年了,自觉学到的东西不多,最近常常在反思,因为在一家产品公司,产品效果不是很好,所以就比较闲了,于是最近在疯狂找东西学,所以找了郭霖大神第一行代码来看,发现还是有一些知识点不懂的,也有一些知识点因为工作不常用所以略为生疏了,所以接下来的日子就是一边看书一边总结了,每天进步一点点,不为什么,就为找个漂亮点的老婆,这篇文章部分总结自郭霖《第一行代码》第五章 全局大喇叭,详解广播机制和网上的一些资料。如果侵权麻烦联系本人即删。


广播机制

  • 广播

    按发送顺序

    • 标准广播 –> 完全异步执行的广播,所有广播接收器几乎同时收到,效率高,无法截断。
    • 有序广播 –> 同步执行的广播,按优先级顺序发送,同一时间只有一个广播接收,前面的广播可以截断后面的。

    按发送范围

    • 全局广播 –> 发出的广播可以被其他任何的任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播,数据不安全。
    • 本地广播 –> 只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,其他软件不会监听到我们的广播数据。
  • 广播接收器
    • 动态注册 –> 在代码中注册,必须启动软件后才能接收到广播;此外,动态注册的广播接收器一定都要取消注册。
    • 静态注册 –> AndroidManifest.xml 中注册,程序未启动就可以监听,例如很常用的开机启动监听。

1.1标准广播 其实也就是无序广播,一起发送给所有人

//新建一个 MyBroadcastReceiver继承自 BroadcastReceiver,代码如下所示:
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceiver",
        Toast.LENGTH_SHORT).show();
    }
}
//AndroidManifest.xml 注册自己的广播接收器
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest"
    android:versionCode="1"
    android:versionName="1.0" >
    ……
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        ……
        <!-- MyBroadcastReceiver 接 收 一 条 值 为 com.example.broadcasttest.
MY_BROADCAST的广播-->
        <receiver android:name=".MyBroadcastReceiver">
            <intent-filter>
            <action android:name="com.example.broadcasttest. MY_BROADCAST"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>
//activity_main.xml布局文件  点击按钮发送广播
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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>
//程序入口
public class MainActivity extends Activity {
    ……
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        //点击按钮就发出标准广播。
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //intent还可以携带其他一些数据的。
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                //标准广播和有序广播差别就是发送广播的方法不一样,后者用的是sendOrderedBroadcast(intent,null);
                sendBroadcast(intent);
            }
        });
        ……
    }
    ……
}

1.2无序广播 可以通过在xml文件配置设置优先级来优先获取广播,再让自己决定是否要把广播传递下去

这个demo1.2是用来接收 demo1.1自定义广播,因为除了系统发出的广播我们可以接收,自己程序定义的广播(demo1.1中的)我们demo1.2也是可以监听到的。

//新建一个广播接收者,当1.1中的demo启动,会触发这里的接收器,因为在Androidmanifest.xml文件里那边设置的action和demo1一样。
public class AnotherBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in AnotherBroadcastReceiver",
        Toast.LENGTH_SHORT).show();
    }
}

//Androidmanifest.xml配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest2"
    android:versionCode="1"
    android:versionName="1.0" >
    ……
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        ……
        <!--AnotherBroadcastReceiver接受的和demo1筛选的是同一个活动-->
        <receiver android:name=".AnotherBroadcastReceiver" >
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

//程序入口 
public class MainActivity extends Activity {
    ……
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                //有序广播,但是这里没啥用,因为没设置优先级,也没进行截断广播的操作,但是可以做些事情,看下面的deom。
                sendOrderedBroadcast(intent, null);
            }
        });
        ……
    }
    ……
}

稍微修改demo1.2就可以看到如何截断广播了

//AndroidManifest.xml 修改配置文件
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest"
    android:versionCode="1"
    android:versionName="1.0" >
    ……
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        ……
        <!--这里设置了.AnotherBroadcastReceiver的优先级为100,所以1.1的-->
        <receiver android:name=".AnotherBroadcastReceiver">
            <intent-filter android:priority="100" >
            <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

// 高优先级的截断广播,其下面的无法监听到。
public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received in MyBroadcastReceive",
        Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

1.3 全局广播 上面讲的全局广播。


1.4 本地广播
全局广播有可能会被其他软件监听到,或者其他软件不停的发送一些垃圾广播到我们接收器里,会有安全性问题,所以有Android有一套本地广播的机制,只能在本应用内生效,所以本地广播无法用静态注册的方式,因为静态注册就是为了让程序没启动也能收到广播,不过他用的是LocalBroadcastManager,看代码

    public class MainActivity extends Activity {
        private IntentFilter intentFilter;
        private LocalReceiver localReceiver;
        private LocalBroadcastManager localBroadcastManager;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            localBroadcastManager = LocalBroadcastManager.getInstance(this);
            // 获取实例
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.example.broadcasttest.
        LOCAL_BROADCAST");
                    localBroadcastManager.sendBroadcast(intent); // 发送本地广播
                }
            });
            intentFilter = new IntentFilter();
            intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
            localReceiver = new LocalReceiver();
            localBroadcastManager.registerReceiver(localReceiver, intentFilter);
            // 注册本地广播监听器
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            //一样要取消注册。
            localBroadcastManager.unregisterReceiver(localReceiver);
        }

    class LocalReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast",
            Toast.LENGTH_SHORT).show();
        }
    }
}

2.1动态注册
实现监听网络变化Demo

  1. 创建一个广播接收器,内部类。
  2. 在需要调用activity的类中进行动态注册。
  3. 销毁activity时一定要取消注册广播接收器。
//主入口
public class MainActivity extends Activity {
//活动过滤器
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        //我们的广播接收器想要监听什么广播,符合这个条件的才通过;当网络发生变化,系统发出这条值"android.net.conn.CONNECTIVITY_CHANGE"
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        //第二步注册广播接收器
        registerReceiver(networkChangeReceiver, intentFilter);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //第三步临走前取消注册广播接收器
        unregisterReceiver(networkChangeReceiver);
    }

    /**
     *第一步:内部类,继承自 BroadcastReceiver,并重写父类的 onReceive()方法就行了
    **/
    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();
            }
        }
    }
}

//AndroidManifest.xml 查询系统的网络状态就是需要声明权限 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />
        <!--声明权限-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    ……
</manifest>

2.2静态注册
实现开机启动Demo

/**
*不再使用内部类的方式来定义广播接收器,因为稍后我们需要在AndroidManifest.xml 中将这个广播接收器的类名注册进去。
**/
public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
    }
}

//AndroidManifest.xml 需要申明 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--获取权限-->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".FirstActivity"
            android:label="This is FirstActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--注册广播接收器,在过滤器里面加上活动类型android.intent.action.BOOT_COMPLETED-->
        <receiver android:name=".BootCompleteReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

其实最常用的是通过广播实现 强制下线功能,也可以用来刷新数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值