Android中的廣播用途很廣,是四大組件之一。在android中可以看到它的各種應(yīng)用,從系統(tǒng)發(fā)出的廣播,用戶自定義的廣播等。
這里詳細(xì)記錄下廣播的分類以及使用方法。
廣播,是由兩方面組成一個流程:廣播發(fā)送者、廣播接收者。
有以下場景:
當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生變化時,系統(tǒng)(廣播發(fā)送者)會發(fā)出一條廣播,這條廣播的標(biāo)識是:android.net.conn.CONNECTIVITY_CHANGE。當(dāng)開發(fā)人員(廣播接收者)也添加了這個標(biāo)識,那開發(fā)人員就可以在代碼中接收到這條廣播。廣播接收者可以是多個。
一、廣播的分類,按有無順序區(qū)分,可以分為:標(biāo)準(zhǔn)廣播、有序廣播。
(1)標(biāo)準(zhǔn)廣播。就是多個廣播接收者,接收到廣播是無序的,沒有規(guī)定誰先誰后。按理想狀況來說,是同一時間接收到系統(tǒng)發(fā)出的廣播。
(2)有序廣播。在廣播接收者,注冊添加這條廣播時,有增加了優(yōu)先熟悉的設(shè)置。優(yōu)先級高的先接收,優(yōu)先級高的廣播接收者,還可以控制是否將廣播往下繼續(xù)傳遞;
二、廣播的注冊。
根據(jù)注冊方式不同有靜態(tài)注冊、動態(tài)注冊。下面以接收系統(tǒng)廣播為例:
(1)靜態(tài)注冊:
有兩種方式實現(xiàn):AndroidManifest.xml中注冊+內(nèi)部類;AndroidManifest.xml中注冊+外部類。
這兩種的實現(xiàn)都是在AndroidManifest.xml中注冊,在代碼中寫B(tài)roadCastReceive的重載即可。
以下是,AndroidManifest.xml中注冊+內(nèi)部類:
- <?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, "網(wǎng)絡(luò)已連接", Toast.LENGTH_SHORT).show();
- }
- else {
- Toast.makeText(arg0, "網(wǎng)絡(luò)未連接", Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- }
有幾個要注意的地方:
AndroidManifest.xml區(qū)域:
權(quán)限需要添加,因為我們測試的是網(wǎng)絡(luò)變化(這個系統(tǒng)變化最容易模擬);
receiver中的name不是activity的name,是BroadcastReceiver繼承類的name。如果是內(nèi)部類,則要像上方寫法一樣,用$來得到方法name;
intent-filter中是要過濾下來的廣播,就是你想要接收的廣播標(biāo)識。
代碼紅字標(biāo)識區(qū)域:
廣播接收的內(nèi)部類,需要定義為static。否則會報錯。
那如果我不想把廣播接收類寫為內(nèi)部類,我要寫在外面,方便android工程的其他頁面調(diào)用,可行嗎?
這個也是可以的,我們定義一個獨(dú)立于activity的類,類名我們寫為:BroadReceive。
類的內(nèi)容,如下:
- 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, "網(wǎng)絡(luò)已連接", Toast.LENGTH_SHORT).show();
- }
- else {
- Toast.makeText(paramContext, "網(wǎng)絡(luò)未連接", 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>
與內(nèi)部類方式相比,區(qū)別在上方receive的name,用的是外部類name。
有些同學(xué)還會問,我如果在代碼中,在activity類外,定義一個普通類繼承BroadCastReceiver。能否在AndroidManifest.xml中靜態(tài)注冊。
答案是不行的,你會發(fā)現(xiàn),這里需要static標(biāo)識,而這個類沒辦法加這個static標(biāo)識。
(2)動態(tài)注冊。從上方的靜態(tài)注冊,我們看到還是有挺多要注意的,有的地方也不是很方便靈活。那我們可以考慮用動態(tài)注冊。
動態(tài)注冊,除了權(quán)限外,我們不需要在AndroidManifest.xml中操作其他內(nèi)容,其他的都在代碼中實現(xiàn);
如下:
- 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, "網(wǎng)絡(luò)已連接", Toast.LENGTH_SHORT).show();
- }
- else {
- Toast.makeText(arg0, "網(wǎng)絡(luò)未連接", 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銷毀的時候解除綁定。
與靜態(tài)注冊相比,大家應(yīng)該更習(xí)慣用動態(tài)注冊。
二、廣播使用實例
(1)標(biāo)準(zhǔn)廣播。
上方例子中接收系統(tǒng)廣播,都可以算是標(biāo)準(zhǔn)廣播。因為沒有做優(yōu)先級設(shè)置。為了更好的說明,我們發(fā)送自定義廣播,并接收。
- 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"));
- }
- }
- }
-
- }
代碼里沒有做太多的修改。偷懶了,剛啟動就先注冊一個廣播接收,然后直接就發(fā)送廣播。
你在onReceive里,可以收到廣播的信息。Intent我們知道可以附帶一些內(nèi)容的,我也一起傳了個值過去。
(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();
- }
- }
- }
-
- }
和以前的代碼相比,唯二的區(qū)別就在發(fā)送廣播和截斷廣播的地方。一個是order、abort,按字面意思就是按順序和截斷。
這樣的廣播,到onReceive中就被截斷了,不會再往下傳遞了。
至于廣播出來后,誰第一個接收,是根據(jù)優(yōu)先級來的。100->99->98....,類似這樣的。
(3)本地廣播
這是剛漏了,補(bǔ)上這個的說明。
本地廣播和以上兩個的區(qū)別在于:本地廣播,只供本應(yīng)用使用,有效的提高廣播的安全性。
寫法與以往的寫法沒有太大的區(qū)別:
- 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的定義替換。這就得到我們要的本地廣播。
以上,總結(jié)了我們會遇到的所有廣播形式以及注冊方式,僅供參考。
廣播就到這里。O 。