1.廣播和廣播接收者
為崇仁等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及崇仁網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、崇仁網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
? ? Android中的廣播和廣播接收者相當(dāng)于現(xiàn)實(shí)生活中的電臺(tái)和聽(tīng)收音機(jī)的人,
???Android系統(tǒng)內(nèi)部相當(dāng)于已經(jīng)定義好了電臺(tái), 就是內(nèi)部定義好了一些事件(外撥電話,短信到來(lái)?
?電池電量低 sd卡狀態(tài) 卸載安裝 ?開(kāi)機(jī)啟動(dòng)等等),我們開(kāi)發(fā)者只需要注冊(cè)這個(gè)事件就ok了(注冊(cè)事
?件就是創(chuàng)建廣播接收者之后在清單里配置意圖過(guò)濾器的action屬性,相當(dāng)于聽(tīng)收音機(jī)的人調(diào)頻一樣)
? ?更確切的說(shuō),廣播接收者就是Android系統(tǒng)的全局監(jiān)聽(tīng)者,可以監(jiān)聽(tīng)系統(tǒng)的很多事件,只要廣播
?接收者注冊(cè)了這些事件,就會(huì)被這些事件觸發(fā)。
? ?★廣播接收者被觸發(fā),底層原理應(yīng)該是廣播事件會(huì)利用隱式意圖啟動(dòng)符合條件的廣播接收者.?
?
2.注冊(cè)廣播接收者
? ?注冊(cè)廣播接收者有2種方式,而且一個(gè)廣播接收者配置多個(gè)過(guò)濾動(dòng)作Action。
? ?★第1種:在清單里注冊(cè)
????在配置文件中注冊(cè)的接收者的特點(diǎn)是即使應(yīng)用程序已被關(guān)閉,該接收者依然可接受它感興趣的廣播。
? ? ? ? ? ? ? ? 上面紅色特性,已經(jīng)驗(yàn)證過(guò),確實(shí)如此!
????一般大多數(shù)的廣播接收者都是在清單文件中注冊(cè),只有少量的廣播接收者是在代碼里注冊(cè)
????當(dāng)然可以在清單里注冊(cè)的廣播接收者,也一定能夠在代碼里注冊(cè)。??
????
???★第2種:在Activity里注冊(cè)
?????在Activity中綁定接收者必須依附該應(yīng)用程序存在,或者一個(gè)BroadcastReceiver用于更新UI,就沒(méi)有必要在
????????????? ??程序關(guān)閉時(shí)接收者還運(yùn)行,故無(wú)需在AndroidManifest.xml中注冊(cè)而可以放在Activity中注冊(cè)。?
???? ?操作特別頻繁的廣播事件 ?比如 鎖屏和解鎖這種廣播接收者在清單文件里面注冊(cè)是無(wú)效的
????必需在代碼里注冊(cè),否則會(huì)報(bào)下面這個(gè)異常。
???? ?MainActivity has leaked IntentReceiver
????? ScreenReceiver@b65bb500 that was originally registered here. Are you missing a
? ? ? ?call to unregisterReceiver()??
???? ?代碼里注冊(cè)廣播接收者
???? ?首先,定義一個(gè)類繼承BroadcastReceiver:
????? ? public class ScreenReceiver extends BroadcastReceiver
???? ?下一步,在一個(gè)Activity中注冊(cè)上面定義的廣播接收者??
????????ScreenReceiver?screenReceiver?=?new?ScreenReceiver();
//創(chuàng)建意圖對(duì)象過(guò)濾器
IntentFilter?intentFilter?=?new?IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
//注冊(cè)鎖屏和解鎖廣播
registerReceiver(screenReceiver,?intentFilter);?
3.廣播接收者開(kāi)發(fā)步驟
? ?第1步:定義一個(gè)類繼承廣播接收者,并在清單或代碼里注冊(cè),包括receiver的name屬性、
????? ?過(guò)濾器的Action屬性。
? ? 第2步:復(fù)寫(xiě)定義的廣播接收者類的onReceive方法,定義廣播接收者被觸發(fā)后想實(shí)現(xiàn)的邏輯。
???? ? 一般如果廣播接收者注冊(cè)了多個(gè)事件,還得先判斷一下事件的類型。
????????????public?void?onReceive(Context?context,?Intent?intent)?{??
????????????????//得到事件的類型
String?action?=?intent.getAction();
????????????}案例:注意不同的案例獲取數(shù)據(jù)的方式
4.案例1_IP撥號(hào)器(外撥電話)
? ?■清單配置
????<receiver?android:name="com.itheima.ipdialerListener.OutGoingReceiver"?> ??????<intent-filter> ?????????<!--?配置action?new?outgoing?call?--> ?????????<action?android:name="android.intent.action.NEW_OUTGOING_CALL"/> ??????</intent-filter> ????</receiver>
???■權(quán)限?
?????<uses-permission?android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
???■廣播接收者的接收后的邏輯??
????public?class?OutGoingReceiver?extends?BroadcastReceiver?{
@Override
public?void?onReceive(Context?context,?Intent?intent)?{
//獲取廣播事件的數(shù)據(jù)-電話號(hào)碼
String?phoneNumber?=?getResultData();???//直接調(diào)用BroadcastReceiver的方法
System.out.println("phoneNumber:"?+?phoneNumber);
//假如電話號(hào)碼開(kāi)頭是0,就是長(zhǎng)途。
if(phoneNumber.startsWith("0"))
{
phoneNumber?=?"95128"?+?phoneNumber;
}
//改變廣播當(dāng)前的數(shù)據(jù)-用修改過(guò)后電話號(hào)碼替換。
setResultData(phoneNumber);???//注意這個(gè)方法只能與有序廣播聯(lián)用?
}
????}??將應(yīng)用程序安裝好,撥打一個(gè)手機(jī)號(hào)以0開(kāi)始的電話號(hào)碼0123,點(diǎn)擊撥打按鈕,效果如下所示:
??
5.案例2_sd卡狀態(tài)監(jiān)聽(tīng)
??????
? ?■清單配置
????注意過(guò)濾器里多了一個(gè)<data android:scheme="file"/>
?????<receiver?android:name="com.itheima.sdcard.SDCardReceiver"?> ????????????<intent-filter> ????????????????<action?android:name="android.intent.action.MEDIA_MOUNTED"/> ????????????????<action?android:name="android.intent.action.MEDIA_UNMOUNTED"/> ????????????????<data?android:scheme="file"/> ????????????</intent-filter> ????????</receiver>
???■權(quán)限?
?????無(wú)
???■廣播接收者的接收后的邏輯??
????public?class?SDCardReceiver?extends?BroadcastReceiver?{
???????? @Override
???????? public?void?onReceive(Context?context,?Intent?intent)?{
???????? ????????//因?yàn)榍鍐卫镉?個(gè)action,所以要獲取action的類型。
???????? String?action?=?intent.getAction();
???????? if(Intent.ACTION_MEDIA_MOUNTED.equals(action))
???????? {
???????? System.out.println("sd卡掛載了");
???????? }else?if(Intent.ACTION_MEDIA_UNMOUNTED.equals(action)){
???????? System.out.println("sd卡卸載了");
???????? }else?{
???????? System.out.println("sd監(jiān)聽(tīng)出錯(cuò)了");
???????? }
???????? }
????????}???進(jìn)入2.3這些低版本的模擬器,settings-storage里面可以模擬sd的掛載與卸載。
? ??
6.案例3_短信監(jiān)聽(tīng)器
? ? 短信監(jiān)聽(tīng)的底層原理,應(yīng)該是短信數(shù)據(jù)庫(kù)內(nèi)容提供者者安插了內(nèi)容觀察者,一旦手機(jī)接收到短
? 信,勢(shì)必短信數(shù)據(jù)庫(kù)會(huì)發(fā)生變化,內(nèi)容觀察者分析到了就會(huì)發(fā)送一條短信接收的廣播,并且把短
? 信相關(guān)的信息封裝在了意圖對(duì)象里。?
? ?■清單配置
? ????高版本的ADT提示里沒(méi)有action對(duì)應(yīng)的選項(xiàng),應(yīng)從低版本ADT拷貝action值到清單中。
????<receiver?android:name="com.itheima.msglistener.MsgListener"?> ????????????<intent-filter> ????????????????<action?android:name="android.provider.Telephony.SMS_RECEIVED"/> ????????????</intent-filter> ????????</receiver>
???■權(quán)限?
?????<uses-permission?android:name="android.permission.RECEIVE_SMS"/>
???■廣播接收者的接收后的邏輯??
?????注意SmsMessage對(duì)象所在的包? ?
????//獲取短信數(shù)據(jù),可能有多條短信數(shù)據(jù)吧。
//由此可見(jiàn),短信的數(shù)據(jù)在intent里的封裝的格式是Bundle,也就是map集合。
Object[]?object?=?(Object[])?intent.getExtras().get("pdus");
//創(chuàng)建SmsMessage對(duì)象來(lái)分離短信的各項(xiàng)內(nèi)容?,注意SmsMessage所在的包。
for?(Object?obj?:?object)?{
????//創(chuàng)建SmsMessage實(shí)例,解析短信信息:發(fā)送者、短信內(nèi)容
SmsMessage?smsMessage?=?SmsMessage.createFromPdu((byte[])?obj);
String?messageBody?=?smsMessage.getMessageBody();
String?originatingAddress?=?smsMessage.getOriginatingAddress();
System.out.println("短信發(fā)送者:"?+?originatingAddress);
System.out.println("短信內(nèi)容:"?+?messageBody);
}???
?? ?關(guān)于短信監(jiān)聽(tīng),android2.3版本時(shí)沒(méi)有考慮到安全問(wèn)題,4.0之后,考慮到安全問(wèn)題,廣播接
? 收者需要有一個(gè)啟動(dòng)界面才能生效(但不一定要求界面就要啟動(dòng),也就是說(shuō)只要有個(gè)activity就行了
??)。
? ? 對(duì)于用戶來(lái)說(shuō),在2.3這些低版本設(shè)備上,對(duì)于沒(méi)有界面的短信監(jiān)聽(tīng)?wèi)?yīng)用,如果一旦有短信發(fā)送過(guò)
? 來(lái),應(yīng)用就會(huì)被激活,在setting中的forcestop按鈕也才會(huì)變得可選,可以在setting中點(diǎn)擊這個(gè)按
? 鈕就能關(guān)閉應(yīng)用
? ??
? ? 對(duì)于流氓程序員來(lái)說(shuō),不但可以做個(gè)沒(méi)有啟動(dòng)界面和圖標(biāo)的應(yīng)用,更可以結(jié)合卸載監(jiān)聽(tīng)事件,不讓
? 安裝的流氓應(yīng)用卸載,還可以加個(gè)密碼確認(rèn)之后才能輸入,要多流氓就有多流氓。
?
7.案例4_應(yīng)用安裝與卸載的監(jiān)聽(tīng)
? ?
? ?■清單配置
? ? ?注意過(guò)濾器多了一個(gè)<data android:scheme="package" />
?????<receiver?android:name="com.itheima.packageaddandremove.PackageReceiver"?> ????????????<intent-filter> ????????????????<action?android:name="android.intent.action.PACKAGE_ADDED"?/> ????????????????<action?android:name="android.intent.action.PACKAGE_REMOVED"?/> ????????????????<data?android:scheme="package"?/> ????????????</intent-filter> ????????</receiver>
???■權(quán)限?
?????無(wú)
???■廣播接收者的接收后的邏輯??
????//得到包名
Uri?packageName??=?intent.getData();
//獲取事件類型
String?action?=?intent.getAction();
if("android.intent.action.PACKAGE_ADDED".equals(action))
{
System.out.println(packageName?+?"安裝了。。。。。");
}
else?if("android.intent.action.PACKAGE_REMOVED".equals(action))
{
System.out.println(packageName?+?"卸載了。。。。。");
}? ?
8.案例5_開(kāi)機(jī)啟動(dòng)監(jiān)聽(tīng)
?如果想在廣播接收者里啟動(dòng)activity,必須要為意圖指定一個(gè)任務(wù)棧標(biāo)記。
? ?■清單配置
? ? ??
???■權(quán)限?
????
???■廣播接收者的接收后的邏輯??
????
??開(kāi)機(jī)啟動(dòng)廣播監(jiān)聽(tīng),可以與很多地方相結(jié)合。如啟動(dòng)activity或service,可以在service里又與
?其它的監(jiān)聽(tīng)事件如短信、電話監(jiān)聽(tīng)相結(jié)合,做出電話竊聽(tīng)器這樣子之類的應(yīng)用。
? ?另外,開(kāi)機(jī)啟動(dòng)監(jiān)聽(tīng)比較的費(fèi)時(shí),有時(shí)候其實(shí)是實(shí)現(xiàn)了,但是 Log就是不出信息,可以采用開(kāi)
?啟Activity的方式(記得intent要setFlags),這樣效果就明顯了。
9.電源鍵長(zhǎng)按廣播
? ?定義廣播類:
package?com.done.assistcarrecord.receiver;
import?android.content.BroadcastReceiver;
import?android.content.Context;
import?android.content.Intent;
import?android.util.Log;
import?com.done.assistcarrecord.MyApplication;
import?com.done.assistcarrecord.common.Constants;
import?com.done.assistcarrecord.util.ShellUtil;
import?com.done.assistcarrecord.util.log.ExceptionLogCatcher;
/**
?*?Created?by?Administrator?on?2018/4/15?0015.
?*?監(jiān)聽(tīng)電源長(zhǎng)按,防止模擬點(diǎn)擊事件時(shí)誤操作點(diǎn)擊了飛行模式。
?*/
public?class?PowerBroadcastReceiver?extends?BroadcastReceiver?{
????private?static?final?String?TAG?=?"PowerBroadcastReceiver";
????public?static?boolean?isPowerDialogShowed?=?false;????????????????//是否出現(xiàn)電源長(zhǎng)按界面
????@Override
????public?void?onReceive(Context?context,?Intent?intent)?{
????????//你自己先把?reasons?==?homekey?和?長(zhǎng)按homekey?排除,剩下的做下面的處理
????????String?reason?=?intent.getStringExtra("reason");
????????if?(intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)){
????????????System.out.println("Intent.ACTION_CLOSE_SYSTEM_DIALOGS?:?"?+?intent.getStringExtra("reason"));
????????????if?(intent.getExtras()!=null?&&?intent.getExtras().getBoolean("myReason")){
????????????}else?if?(reason?!=?null){
????????????????if?(reason.equalsIgnoreCase("globalactions")){
????????????????????//監(jiān)聽(tīng)電源長(zhǎng)按鍵的方法:
????????????????????Intent?myIntent?=?new?Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
????????????????????myIntent.putExtra("myReason",?true);
????????????????????context.sendOrderedBroadcast(myIntent,?null);
????????????????????Log.e(TAG,?"onReceive:?電源??鍵被長(zhǎng)按");
????????????????????ExceptionLogCatcher.getInstance().put("電源??鍵被長(zhǎng)按");
????????????????????isPowerDialogShowed?=?true;
????????????????????MyApplication.gHANDLER.postDelayed(new?Runnable()?{
????????????????????????@Override
????????????????????????public?void?run()?{
????????????????????????????ShellUtil.execCommand(Constants.CLICK_CANCEL_POWER_LONG_PRESS_DIALOG,?true);
????????????????????????}
????????????????????},500);
????????????????????isPowerDialogShowed?=?false;
????????????????????ExceptionLogCatcher.getInstance().put("模擬關(guān)閉電源對(duì)話框成功");
????????????????}else?if?(reason.equalsIgnoreCase("homekey")){
????????????????????//<span?>監(jiān)聽(tīng)</span><span?>Home鍵的方法</span>
????????????????????//在這里做一些你自己想要的操作,比如重新打開(kāi)自己的鎖屏程序界面,這樣子就不會(huì)消失了
????????????????????Log.e(TAG,?"onReceive:?Home?鍵被觸發(fā)");
????????????????}else?if?(reason.equalsIgnoreCase("recentapps")){
????????????????????//監(jiān)聽(tīng)Home鍵長(zhǎng)按的方法
????????????????????Log.e(TAG,?"onReceive:?Home?鍵被長(zhǎng)按");
????????????????}
????????????}
????????}
????}
}????在代碼里注冊(cè)(好像在清單里注冊(cè),是接收不到廣播的)
@Override
public?void?onCreate()?{
????//監(jiān)聽(tīng)長(zhǎng)按事件
????final?IntentFilter?homeFilter?=?new?IntentFilter(
????????????Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
????powerBroadcastReceiver?=?new?PowerBroadcastReceiver();
????registerReceiver(powerBroadcastReceiver,?homeFilter);????一般在onDestroy方法里注銷廣播
if(powerBroadcastReceiver?!=?null){
????unregisterReceiver(powerBroadcastReceiver);
????powerBroadcastReceiver?=?null;
}????
10.TIME_TICK 廣播
? ??https://blog.csdn.net/mrleeapple/article/details/50525236? (系統(tǒng)源碼明確指出不能靜態(tài)注冊(cè))
####################################################################################
上面講到幾個(gè)案例,都有一個(gè)共同的特點(diǎn):廣播都是由系統(tǒng)發(fā)送的。那么可以自己定義并發(fā)送廣播嗎?
查看API會(huì)發(fā)現(xiàn)Context類有發(fā)送廣播的方法,Activity和Service都繼承了Context,所以這兩個(gè)對(duì)象
都可以發(fā)送廣播,或者只要有Context對(duì)象的對(duì)象都可以發(fā)送廣播。廣播就是在發(fā)送Intent,Intent用
來(lái)封裝數(shù)據(jù)并且過(guò)濾廣播接收者,發(fā)送廣播有2種方式:(系統(tǒng)發(fā)送廣播也是用的這2個(gè)方法)
1.發(fā)送無(wú)序廣播
? ?■發(fā)送廣播代碼:sendBroadcast
?public?void?sendUnOrder(String?content)
????{
???? Intent?intent?=?new?Intent();
???? //注意設(shè)置意圖對(duì)象的action,以便過(guò)濾發(fā)送給哪個(gè)廣播接收者。
???? intent.setAction("com.itheima.UNORDER_SEND");
???? intent.putExtra("content",?content);
???? //無(wú)序廣播的發(fā)送方法
???? sendBroadcast(intent);
????
????}? ?■廣播接收者清單配置: ???
? ?只要定義一個(gè)廣播接收者,在清單里配置它的action屬性和發(fā)送代碼里的action參數(shù)一樣,發(fā)送廣
?播的方法就會(huì)將意圖Intent發(fā)送給符合條件的廣播接收者的onReceive參數(shù)里,這也印證了為什么廣播
?接收者的接收方法里會(huì)有一個(gè)Intent參數(shù)的原因:onReceive參數(shù)里的Intent就是發(fā)送這個(gè)廣播的對(duì)象
?傳遞的Intent。
? ?
2.發(fā)送有序廣播
?■發(fā)送廣播代碼:sendOrderedBroadcast? ??
?public?void?sendOrder(String?content)
????{
???? Intent?intent?=?new?Intent();
???? intent.setAction("com.itheima.ORDER_SEND");
???? //注意有序廣播的發(fā)送方法
???? sendOrderedBroadcast(intent,?null,?new?FinalReceiver(),?null,?1,?content,?null);
????}??■廣播接收者清單配置:??
????和接收無(wú)序廣播的廣播接收者不同,接收有序廣播的廣播接收者的過(guò)濾器除了要配置action
? ?標(biāo)簽之外,過(guò)濾器本身還要設(shè)置priority屬性,表示過(guò)濾器的優(yōu)先級(jí),優(yōu)先級(jí)高的過(guò)濾器的廣播
? ?接收者會(huì)優(yōu)先接收到廣播。
????終極接收者無(wú)須在清單配置任何信息,連receiver也不用配置。
? ? ?
? ?■廣播接收者接收廣播代碼:?
?????
??
????
3.有序廣播與無(wú)序廣播的區(qū)別(**********重點(diǎn)***********)
??■有序廣播?
????廣播的數(shù)據(jù)可以被修改,廣播可以被攔截,但是終極接收者仍然可以接受到。
??■無(wú)序廣播??
??? ?廣播的數(shù)據(jù)不可以被修改,廣播不可以被攔截。
?
--------------------------------廣播的一些異常------------------------------------
1)IllegalStateException: Can not perform this action after onSaveInstanceState
? ??http://www.tuicool.com/articles/yU3Yji
?http://stackoverflow.com/questions/7575921/illegalstateexception-can-not-perform-this-action-after-onsaveinstancestate-wit
??
? 一是要解注冊(cè)廣播,二是在fragmentManager提交的時(shí)候采用
transaction.commitAllowingStateLoss();
2)https://blog.csdn.net/yuanyuan_186/article/details/17389699
3)收不到開(kāi)機(jī)廣播:????
?????https://blog.csdn.net/baidu_27196493/article/details/78269674
4)android:報(bào)Activity has leaked IntentReceiver或者receiver is not registered錯(cuò)誤 - yuanyuan_186的專欄 - CSDN博客
?
分享名稱:AndroidDay07四大組件之廣播接收者BroadcastReceiver
文章URL:http://www.chinadenli.net/article0/iiihio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、小程序開(kāi)發(fā)、App設(shè)計(jì)、網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化、網(wǎng)頁(yè)設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)