Android中BroadcastReceiver广播使用及注意点

android中的广播用途很广,是四大组件之一。在android中可以看到它的各种应用,从系统发出的广播,用户自定义的广播等。

这里详细记录下广播的分类以及使用方法。

广播,是由两方面组成一个流程:广播发送者、广播接收者。

有以下场景:

当网络状态发生变化时,系统(广播发送者)会发出一条广播,这条广播的标识是:android.net.conn.CONNECTIVITY_CHANGE。当开发人员(广播接收者)也添加了这个标识,那开发人员就可以在代码中接收到这条广播。广播接收者可以是多个。


一、广播的分类,按有无顺序区分,可以分为:标准广播、有序广播。

(1)标准广播。就是多个广播接收者,接收到广播是无序的,没有规定谁先谁后。按理想状况来说,是同一时间接收到系统发出的广播。

(2)有序广播。在广播接收者,注册添加这条广播时,有增加了优先熟悉的设置。优先级高的先接收,优先级高的广播接收者,还可以控制是否将广播往下继续传递;

二、广播的注册。

根据注册方式不同有静态注册、动态注册。下面以接收系统广播为例:

(1)静态注册:

有两种方式实现:AndroidManifest.xml中注册+内部类;AndroidManifest.xml中注册+外部类。

这两种的实现都是在AndroidManifest.xml中注册,在代码中写BroadCastReceive的重载即可。

以下是,AndroidManifest.xml中注册+内部类:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest_csdn"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
  <span style="color:#cc0000;"> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/></span>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.broadcasttest_csdn.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.example.broadcasttest_csdn.MainActivity$myBroadCast">
            <intent-filter >
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

package com.example.broadcasttest_csdn;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.R.anim;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

	
	BroadcastReceiver bReceiver;
	IntentFilter iFilter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /*
        iFilter=new IntentFilter();
        iFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        bReceiver=new myBroadCast();
        registerReceiver(bReceiver, iFilter);
        */
    }
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		//unregisterReceiver(bReceiver);
	}

	 public static  class myBroadCast extends BroadcastReceiver
	 {
	 	@Override
	 	public void onReceive(Context arg0, Intent arg1) {
	 		// TODO Auto-generated method stub
	 		ConnectivityManager connectivityManager=(ConnectivityManager)arg0.getSystemService(arg0.CONNECTIVITY_SERVICE);
	 		NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
	 		if(networkInfo!=null&&networkInfo.isAvailable())
	 		{
	 			Toast.makeText(arg0, "网络已连接", Toast.LENGTH_SHORT).show();
	 		}
	 		else {
	 			Toast.makeText(arg0, "网络未连接", Toast.LENGTH_SHORT).show();
	 		}
	 	}
	 }
	
}

有几个要注意的地方:

AndroidManifest.xml区域:

权限需要添加,因为我们测试的是网络变化(这个系统变化最容易模拟);

receiver中的name不是activity的name,是BroadcastReceiver继承类的name。如果是内部类,则要像上方写法一样,用$来得到方法name;

intent-filter中是要过滤下来的广播,就是你想要接收的广播标识。

代码红字标识区域:

广播接收的内部类,需要定义为static。否则会报错。


那如果我不想把广播接收类写为内部类,我要写在外面,方便android工程的其他页面调用,可行吗?

这个也是可以的,我们定义一个独立于activity的类,类名我们写为:BroadReceive。

类的内容,如下:

package com.example.broadcasttest_csdn;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Toast;

public class BroadReceive extends BroadcastReceiver{

	@Override
	public void onReceive(Context paramContext, Intent paramIntent) {
		// TODO Auto-generated method stub
		ConnectivityManager connectivityManager=(ConnectivityManager)paramContext.getSystemService(paramContext.CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
		if(networkInfo!=null&&networkInfo.isAvailable())
		{
			Toast.makeText(paramContext, "网络已连接", Toast.LENGTH_SHORT).show();
		}
		else {
			Toast.makeText(paramContext, "网络未连接", Toast.LENGTH_SHORT).show();
		}
		
	
	}

}
AndroidManifest.xml的定义如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest_csdn"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.broadcasttest_csdn.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.example.broadcasttest_csdn.BroadReceive">
            <intent-filter >
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>
与内部类方式相比,区别在上方receive的name,用的是外部类name。
有些同学还会问,我如果在代码中,在activity类外,定义一个普通类继承BroadCastReceiver。能否在AndroidManifest.xml中静态注册。

答案是不行的,你会发现,这里需要static标识,而这个类没办法加这个static标识。


(2)动态注册。从上方的静态注册,我们看到还是有挺多要注意的,有的地方也不是很方便灵活。那我们可以考虑用动态注册。

动态注册,除了权限外,我们不需要在AndroidManifest.xml中操作其他内容,其他的都在代码中实现;

如下:

package com.example.broadcasttest_csdn;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.R.anim;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

	
	BroadcastReceiver bReceiver;
	IntentFilter iFilter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        iFilter=new IntentFilter();
        iFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        bReceiver=new myBroadCast();
        registerReceiver(bReceiver, iFilter);
        
    }
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		unregisterReceiver(bReceiver);
	}

	 public static  class myBroadCast extends BroadcastReceiver
	 {
	 	@Override
	 	public void onReceive(Context arg0, Intent arg1) {
	 		// TODO Auto-generated method stub
	 		ConnectivityManager connectivityManager=(ConnectivityManager)arg0.getSystemService(arg0.CONNECTIVITY_SERVICE);
	 		NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
	 		if(networkInfo!=null&&networkInfo.isAvailable())
	 		{
	 			Toast.makeText(arg0, "网络已连接", Toast.LENGTH_SHORT).show();
	 		}
	 		else {
	 			Toast.makeText(arg0, "网络未连接", Toast.LENGTH_SHORT).show();
	 		}
	 	}
	 }
	
}

AndroidManifest.xml的定义如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest_csdn"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.broadcasttest_csdn.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>


如代码中几个步骤,定义过滤器intent-filter、定义广播接收类、在activity开启的时候绑定二者、在activity销毁的时候解除绑定。

与静态注册相比,大家应该更习惯用动态注册。

二、广播使用实例

(1)标准广播。

上方例子中接收系统广播,都可以算是标准广播。因为没有做优先级设置。为了更好的说明,我们发送自定义广播,并接收。

package com.example.broadcasttest_csdn;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.R.anim;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

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

        iFilter=new IntentFilter();
        iFilter.addAction("myAction");
        bReceiver=new myBroadCast();
        registerReceiver(bReceiver, iFilter);
        
        Intent intent=new Intent();
        intent.setAction("myAction");
        intent.putExtra("info", "附带信息");
        sendBroadcast(intent);
        
    }
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		unregisterReceiver(bReceiver);
	}

	 public static  class myBroadCast extends BroadcastReceiver
	 {
	 	@Override
	 	public void onReceive(Context arg0, Intent arg1) {
	 		// TODO Auto-generated method stub
	 		if(arg1!=null)
	 		{
	 			Log.i("Action", arg1.getAction()) ;
	 			Log.i("获取的信息", arg1.getStringExtra("info"));
	 		}
	 	}
	 }
	
}

代码里没有做太多的修改。偷懒了,刚启动就先注册一个广播接收,然后直接就发送广播。

你在onReceive里,可以收到广播的信息。Intent我们知道可以附带一些内容的,我也一起传了个值过去。

(2)有序广播

package com.example.broadcasttest_csdn;

import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.R.anim;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

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

        iFilter=new IntentFilter();
        iFilter.addAction("myAction");
       iFilter.setPriority(100);
        bReceiver=new myBroadCast();
        registerReceiver(bReceiver, iFilter);
        
        Intent intent=new Intent();
        intent.setAction("myAction");
        intent.putExtra("info", "附带信息");
       sendOrderedBroadcast(intent, null);
        
    }
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		unregisterReceiver(bReceiver);
	}

	 public static  class myBroadCast extends BroadcastReceiver
	 {
	 	@Override
	 	public void onReceive(Context arg0, Intent arg1) {
	 		// TODO Auto-generated method stub
	 		if(arg1!=null)
	 		{
	 			Log.i("Action", arg1.getAction()) ;
	 			Log.i("获取的信息", arg1.getStringExtra("info"));
	 			abortBroadcast();
	 		}
	 	}
	 }
	
}
和以前的代码相比,唯二的区别就在发送广播和截断广播的地方。一个是order、abort,按字面意思就是按顺序和截断。

这样的广播,到onReceive中就被截断了,不会再往下传递了。

至于广播出来后,谁第一个接收,是根据优先级来的。100->99->98....,类似这样的。

(3)本地广播

这是刚漏了,补上这个的说明。

本地广播和以上两个的区别在于:本地广播,只供本应用使用,有效的提高广播的安全性。

写法与以往的写法没有太大的区别:

package com.example.broadcasttest_csdn;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

public class MainActivity extends Activity {

	LocalBroadcastManager localBroadcastManager;
	
	BroadcastReceiver bReceiver;
	IntentFilter iFilter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        iFilter=new IntentFilter();
        iFilter.addAction("myAction");
        iFilter.setPriority(100);
        bReceiver=new myBroadCast();
        //registerReceiver(bReceiver, iFilter);
      localBroadcastManager=LocalBroadcastManager.getInstance(MainActivity.this);
        localBroadcastManager.registerReceiver(bReceiver, iFilter);
        
        Intent intent=new Intent();
        intent.setAction("myAction");
        intent.putExtra("info", "附带信息");
        //sendOrderedBroadcast(intent, null);
        localBroadcastManager.sendBroadcastSync(intent);
    }
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		//unregisterReceiver(bReceiver);
		localBroadcastManager.unregisterReceiver(bReceiver);
	}

	 public static  class myBroadCast extends BroadcastReceiver
	 {
	 	@Override
	 	public void onReceive(Context arg0, Intent arg1) {
	 		// TODO Auto-generated method stub
	 		if(arg1!=null)
	 		{
	 			Log.i("Action", arg1.getAction()) ;
	 			Log.i("获取的信息", arg1.getStringExtra("info"));
	 			//abortBroadcast();
	 		}
	 	}
	 }
	
}


将原来的BroadCastReceiver替换,就是修改的地方。将有些定义注释,用local的定义替换。这就得到我们要的本地广播。

以上,总结了我们会遇到的所有广播形式以及注册方式,仅供参考。

广播就到这里。O 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值