廣播(Broadcast)是一種廣泛運用的在應(yīng)用程序之間傳輸信息的機制,在 Android 里面有各種各樣的廣播汞窗,比如電池的使用狀態(tài),電話的接收和短信的接收都會產(chǎn)生一個廣播,應(yīng)用程序也可以接受廣播并做出程序邏輯上的處理, 比如我們需要讓應(yīng)用程序開機自動啟動示启,其實就是應(yīng)用了廣播的知識。
廣播的三要素分別是:
1.廣播(Broadcast) - 用于發(fā)送廣播溯捆;
2.廣播接收器(BroadcastReceiver) - 用于接收廣播丑搔;
3.意圖(Intent)-用于保存廣播相關(guān)信息的媒介。
下面是我從網(wǎng)上搜集的一些廣播的知識點:
1.普通廣播
普通廣播是完全異步的提揍,可以在同一時刻(邏輯上)被所有廣播接收者接收到啤月,消息傳遞的效率比較高,但缺點是接收者不能將處理結(jié)果傳遞給下一個接收者劳跃,并且無法終止廣播Intent的傳播谎仲。
2.有序廣播
有序廣播是按照接收者聲明的優(yōu)先級別(聲明在intent-filter元素的android:priority屬性中,數(shù)越大優(yōu)先級別越高,取值范圍:-1000到1000刨仑。也可以調(diào)用IntentFilter對象的setPriority()進行設(shè)置)郑诺,被接收者依次接收廣播。如:A的級別高于B, B的級別高于C,那么杉武,廣播先傳給A辙诞,再傳給B,最后傳給C轻抱。A得到廣播后飞涂,可以往廣播里存入數(shù)據(jù),當(dāng)廣播傳給B時,nB可以從廣播中得到A存入的數(shù)據(jù)祈搜。
3系統(tǒng)廣播
系統(tǒng)廣播是Android內(nèi)置的廣播较店,滿足一定條件后系統(tǒng)會自動發(fā)送這個廣播,不需要我們再定義發(fā)送容燕,只需要用的時候接收就可以了梁呈,比如手機開機完成后會發(fā)出一條廣播,電池的電量發(fā)生變化會發(fā)出一 條廣播,時間或時區(qū)發(fā)生改變也會發(fā)出一條廣播,攝像頭按被按下會觸發(fā)廣播等等蘸秘。
4自定義廣播
自定義廣播是用戶可以自己定義發(fā)送一個廣播官卡,看到很多書籍都是這么講蝗茁,可以我一直在思考為什么需要自定義廣播,或者說自定義廣播在Android程序中一般是用在什么地方寻咒,因為廣播是為了給不同的組件中通信而使用的例如service 與 Activity 不同的進程中,或者不同的應(yīng)用程序中就會使用廣播機制來通信的评甜。
5本地廣播
系統(tǒng)廣播和自定義廣播都屬于全局廣播,即發(fā)出的廣播可以被其他任何 的任何應(yīng)用程序接收到, 并且我們也可以接收來自于其他任何應(yīng)用程序的廣播。這樣就很容易會引起安全性的問題, 比如說我們發(fā)送的一些攜帶關(guān)鍵性數(shù)據(jù)的廣播有可能被其他的應(yīng)用程序截獲,或者其他的程序不停地向我們的廣播接收器里發(fā)送各種垃圾廣播仔涩。
為了能夠簡單地解決廣播的安全性問題,Android 引入了一套本地廣播機制,使用這個機制發(fā)出的廣播只能夠在應(yīng)用程序的內(nèi)部進行傳遞,并且廣播接收器也只能接收來自本應(yīng)用程序發(fā)出的廣播,這樣所有的安全性問題就都不存在了忍坷。
6動態(tài)注冊廣播
動態(tài)注冊就是在程序中使用Context.registerReceiver注冊。動態(tài)注冊的廣播接收器可以自由地控制注冊與注銷,在靈活性方面有很大的優(yōu)勢,但是它也存在著一個缺點,即必須要在程序啟動之后才能接收到廣播,因為注冊的邏輯是寫在 onCreate()方法中的熔脂。
7靜態(tài)注冊廣播
在AndroidManifest.xml中注冊廣播稱之為靜態(tài)注冊佩研,靜態(tài)注冊是常駐型 ,也就是說當(dāng)應(yīng)用程序關(guān)閉后霞揉,如果有信息廣播來旬薯,程序也會被系統(tǒng)調(diào)用自動運行,所以一些系統(tǒng)級別的廣播比如開機啟動廣播就必須要用到靜態(tài)注冊的方法适秩,而有些系統(tǒng)廣播也是可以動態(tài)注冊的绊序,比如電量變化廣播等可以在程序啟動后監(jiān)聽即可。
下面我通過例子簡單的介紹一下廣播機理:
(1)首先舉一個系統(tǒng)廣播的例子秽荞,這里我們通過靜態(tài)注冊廣播的方式來完成
首先要再AndroidManifest.xml中注冊廣播接收機
<pre>
//注冊廣播接收機骤公,監(jiān)聽開機廣播
<receiver android:name=".MyBroadcastReceive">
<intent-filter>
//通過android:name來指定具體注冊哪一個廣播接收器
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</pre>
新建廣播接收機,創(chuàng)建MyBroadcastReceive.java
<pre>
public class MyBroadcastReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"開機啟動",Toast.LENGTH_LONG).show();
}
}
</pre>
運行程序候扬跋,重啟虛擬機阶捆,在開機時可以看到“開機啟動”的Toast
(2)下面我們通過靜態(tài)注冊廣播的方式完成自定義廣播
首先在AndroidManifest.xml文件中靜態(tài)注冊自定廣播接收機
<pre>
<receiver android:name=".DiyBroadReceive">
<intent-filter>
//通過android:name來指定具體注冊哪一個廣播接收器,這里可以自己任意指定name
<action android:name="linus.diyBroadReceive" />
</intent-filter>
</receiver>
</pre>
創(chuàng)建自定義廣播接收機钦听,新建DiyBroadReceive.java
<pre>
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("linus.diyBroadReceive");
intent.putExtra("name", "linus");
sendBroadcast(intent);
}
});
</pre>
(3)下面我們來看一下如何動態(tài)注冊一個自定義廣播接收機
<pre>
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//實例化廣播接收器
dynamicBroadReceive = new DynamicBroadReceive();
//實例化意圖過濾器
filter = new IntentFilter();
//為過濾器添加一個定義的廣播洒试,當(dāng)然這里也可以填系統(tǒng)廣播
filter.addAction("linus.dynamicBroadReceive");
//可以通過setPriority()設(shè)置動態(tài)廣播的優(yōu)先級,優(yōu)先級取值范圍是-1000到1000
//注意的是的靜態(tài)注冊的廣播要快于動態(tài)注冊的廣播,不管動態(tài)注冊的優(yōu)先級設(shè)置的多高,不管靜態(tài)注冊的優(yōu)先級有多低
filter.setPriority(1000);
//第一步朴上,注冊廣播
registerReceiver(dynamicBroadReceive, filter);
//第二部垒棋,發(fā)送廣播
Intent intent = new Intent();
intent.setAction("linus.dynamicBroadReceive");
intent.putExtra("name","linus-dynamic");
sendBroadcast(intent);
}
});
</pre>
創(chuàng)建自定義廣播,新建DynamicBroadReceive.java
<pre>
public class DynamicBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//第三部痪宰,接收廣播
String name = intent.getExtras().getString("name");
Toast.makeText(context,"動態(tài)注冊廣播后叼架,接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
動態(tài)注冊廣播,在結(jié)束時必須注銷廣播
<pre>
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dynamicBroadReceive);
}
</pre>
(4)下面在舉例說明一下本地廣播酵镜,本地廣播無法通過靜態(tài)注冊完成廣播注冊碉碉。因為當(dāng)廣播到來時柴钻,應(yīng)用一定時啟動的淮韭。本地廣播一般時通過LocalBroadcastManager進行管理的
<pre>
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
localBroadcastManager = LocalBroadcastManager.getInstance(getBaseContext());
localBroadReceive = new LocalBroadReceive();
filter = new IntentFilter();
filter.addAction("linus.localBroadReceive");
localBroadcastManager.registerReceiver(localBroadReceive,filter);
Intent intent = new Intent();
intent.setAction("linus.localBroadReceive");
intent.putExtra("name","linus-local");
localBroadcastManager.sendBroadcast(intent);
}
});
</pre>
創(chuàng)建本地廣播接收機,創(chuàng)建LocalBroadReceive.java
<pre>
public class LocalBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"本地廣播接收到的name是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
本地廣播在結(jié)束時贴届,也是需要注銷廣播的靠粪。
<pre>
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localBroadReceive);
}
</pre>
(5)有序廣播就是按照廣播的優(yōu)先級進行廣播蜡吧,不同的應(yīng)用接收到廣播的先后順序不同。同時先接收到廣播的應(yīng)用可以向后接收到的廣播傳遞數(shù)據(jù)占键。這里就不舉例說明了昔善。
為了方面大家實踐測試,我將整個demo的源碼分享一下畔乙。
MainActivity.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn1, btn2,btn3;
//定義意圖過濾器
private IntentFilter filter;
//定義廣播接收器
DynamicBroadReceive dynamicBroadReceive;
LocalBroadReceive localBroadReceive;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn3 = (Button) findViewById(R.id.btn3);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("linus.diyBroadReceive");
intent.putExtra("name", "linus");
sendBroadcast(intent);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//實例化廣播接收器
dynamicBroadReceive = new DynamicBroadReceive();
//實例化意圖過濾器
filter = new IntentFilter();
//為過濾器添加一個定義的廣播君仆,當(dāng)然這里也可以填系統(tǒng)廣播
filter.addAction("linus.dynamicBroadReceive");
//可以通過setPriority()設(shè)置動態(tài)廣播的優(yōu)先級,優(yōu)先級取值范圍是-1000到1000
//注意的是的靜態(tài)注冊的廣播要快于動態(tài)注冊的廣播,不管動態(tài)注冊的優(yōu)先級設(shè)置的多高,不管靜態(tài)注冊的優(yōu)先級有多低
filter.setPriority(1000);
//注冊廣播
registerReceiver(dynamicBroadReceive, filter);
Intent intent = new Intent();
intent.setAction("linus.dynamicBroadReceive");
intent.putExtra("name","linus-dynamic");
sendBroadcast(intent);
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
localBroadcastManager = LocalBroadcastManager.getInstance(getBaseContext());
localBroadReceive = new LocalBroadReceive();
filter = new IntentFilter();
filter.addAction("linus.localBroadReceive");
localBroadcastManager.registerReceiver(localBroadReceive,filter);
Intent intent = new Intent();
intent.setAction("linus.localBroadReceive");
intent.putExtra("name","linus-local");
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dynamicBroadReceive);
localBroadcastManager.unregisterReceiver(localBroadReceive);
}
}
</pre>
activity_main.xml
<pre>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="linuszhao.js.one.jsbroadcast.MainActivity"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="發(fā)起自定義廣播"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="動態(tài)發(fā)送廣播"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:text="發(fā)起本地廣播"/>
</LinearLayout>
</pre>
Androidmanifest.xml
<pre>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="linuszhao.js.one.jsbroadcast">
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
//注冊廣播接收機牲距,監(jiān)聽開機廣播
<receiver android:name=".MyBroadcastReceive">
<intent-filter>
//通過android:name來指定具體注冊哪一個廣播接收器
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
//注冊廣播接收機
<receiver android:name=".DiyBroadReceive">
<intent-filter>
//通過android:name來指定具體注冊哪一個廣播接收器返咱,這里可以自己任意指定name
<action android:name="linus.diyBroadReceive" />
</intent-filter>
</receiver>
</application>
</manifest>
</pre>
DiyBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class DiyBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"自定義廣播接收機接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
MyBroadcastReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class MyBroadcastReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"開機啟動",Toast.LENGTH_LONG).show();
}
}
</pre>
DynamicBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class DynamicBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"動態(tài)注冊廣播后,接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
LocalBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class LocalBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"本地廣播接收到的name是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>