Android应用开发-广播和服务
生活随笔
收集整理的這篇文章主要介紹了
Android应用开发-广播和服务
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
廣播
- 廣播的概念
- 現(xiàn)實(shí):電臺通過發(fā)送廣播發(fā)布消息,買個收音機(jī),就能收聽
- Android:系統(tǒng)在產(chǎn)生某個事件時發(fā)送廣播,應(yīng)用程序使用廣播接收者接收這個廣播,就知道系統(tǒng)產(chǎn)生了什么事件。
Android系統(tǒng)在運(yùn)行的過程中,會產(chǎn)生很多事件,比如開機(jī)、電量改變、收發(fā)短信、撥打電話、屏幕解鎖
IP撥號器
原理:接收撥打電話的廣播,修改廣播內(nèi)攜帶的電話號碼
定義廣播接收者接收打電話廣播
public class CallReceiver extends BroadcastReceiver {//當(dāng)廣播接收者接收到廣播時,此方法會調(diào)用@Overridepublic void onReceive(Context context, Intent intent) {//拿到用戶撥打的號碼String number = getResultData();//修改廣播內(nèi)的號碼setResultData("17951" + number);} }- 在清單文件中定義該廣播接收者接收的廣播類型
- 接收打電話廣播需要權(quán)限
- 即使廣播接收者的進(jìn)程沒有啟動,當(dāng)系統(tǒng)發(fā)送的廣播可以被該接收者接收時,系統(tǒng)會自動啟動該接收者所在的進(jìn)程
案例1:IP撥號器
public class CallReceiver extends BroadcastReceiver {//接收到廣播時就會調(diào)用@Overridepublic void onReceive(Context context, Intent intent) {//添加IP線路//在打電話廣播中,會攜帶撥打的電話的號碼,通過以下代碼獲取到String number = getResultData();if(number.startsWith("0")){SharedPreferences sp = context.getSharedPreferences("ip", Context.MODE_PRIVATE);String ipNumber = sp.getString("ipNumber", "");//把IP線路號碼添加至用戶撥打號碼的前面number = ipNumber + number;//把新的號碼重新放入廣播中setResultData(number);abortBroadcast();} } } public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){EditText et = (EditText) findViewById(R.id.et);SharedPreferences sp = getSharedPreferences("ip", MODE_PRIVATE);sp.edit().putString("ipNumber", et.getText().toString()).commit();} }短信攔截器
系統(tǒng)收到短信時會產(chǎn)生一條廣播,廣播中包含了短信的號碼和內(nèi)容
- 定義廣播接收者接收短信廣播
- 系統(tǒng)創(chuàng)建廣播時,把短信存放到一個數(shù)組,然后把數(shù)據(jù)以pdus為key存入bundle,再把bundle存入intent
- 清單文件中配置廣播接收者接收的廣播類型,注意要設(shè)置優(yōu)先級屬性,要保證優(yōu)先級高于短信應(yīng)用,才可以實(shí)現(xiàn)攔截
- 添加權(quán)限
<uses-permission android:name=”android.permission.RECEIVE_SMS”/>
- 4.0以后廣播接收者安裝以后必須手動啟動一次,否則不生效
- 4.0以后廣播接收者如果被手動關(guān)閉,就不會再啟動了
案例2:短信防火墻
public class SmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//拿到短信的信息//短信內(nèi)容封裝在intent中Bundle bundle = intent.getExtras();//以pdus為鍵,取出一個object數(shù)組,數(shù)組中的每一個元素,都是一條短信Object[] objects = (Object[]) bundle.get("pdus");//拿到廣播中的所有短信for (Object object : objects) {//通過pdu來構(gòu)造短信SmsMessage sms = SmsMessage.createFromPdu((byte[])object);if(sms.getOriginatingAddress().equals("138438")){//阻止其他廣播接收者收到這條廣播abortBroadcast(); // SmsManager.getDefault().sendTextMessage(sms.getOriginatingAddress(), null, "你是個好人", null, null);} // System.out.println(sms.getMessageBody()); }} }監(jiān)聽SD卡狀態(tài)
- 清單文件中定義廣播接收者接收的類型,監(jiān)聽SD卡常見的三種狀態(tài),所以廣播接收者需要接收三種廣播
- 廣播接收者的定義
勒索軟件
- 接收開機(jī)廣播,在廣播接收者中啟動勒索的Activity
- 清單文件中配置接收開機(jī)廣播
- 權(quán)限
- 定義廣播接收者
- 以上代碼還不能啟動MainActivity,因?yàn)閺V播接收者的啟動,并不會創(chuàng)建任務(wù)棧,那么沒有任務(wù)棧,就無法啟動activity
- 手動設(shè)置創(chuàng)建新任務(wù)棧的flag
監(jiān)聽?wèi)?yīng)用的安裝、卸載、更新
原理:應(yīng)用在安裝卸載更新時,系統(tǒng)會發(fā)送廣播,廣播里會攜帶應(yīng)用的包名
清單文件定義廣播接收者接收的類型,因?yàn)橐O(jiān)聽?wèi)?yīng)用的三個動作,所以需要接收三種廣播
<receiver android:name="com.itheima.app.AppReceiver"><intent-filter ><action android:name="android.intent.action.PACKAGE_ADDED"/><action android:name="android.intent.action.PACKAGE_REPLACED"/><action android:name="android.intent.action.PACKAGE_REMOVED"/><data android:scheme="package"/></intent-filter> </receiver>- 廣播接收者的定義
廣播的兩種類型
- 無序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,并且是沒有先后順序(同時收到)
- 有序廣播:所有跟廣播的intent匹配的廣播接收者都可以收到該廣播,但是會按照廣播接收者的優(yōu)先級來決定接收的先后順序
- 優(yōu)先級的定義:-1000~1000
- 最終接收者:所有廣播接收者都接收到廣播之后,它才接收,并且一定會接收
- abortBroadCast:阻止其他接收者接收這條廣播,類似攔截,只有有序廣播可以被攔截
Service
- 就是默默運(yùn)行在后臺的組件,可以理解為是沒有前臺的activity,適合用來運(yùn)行不需要前臺界面的代碼
- 服務(wù)可以被手動關(guān)閉,不會重啟,但是如果被自動關(guān)閉,內(nèi)存充足就會重啟
- startService啟動服務(wù)的生命周期
- onCreate-onStartCommand-onDestroy
- 重復(fù)的調(diào)用startService會導(dǎo)致onStartCommand被重復(fù)調(diào)用
進(jìn)程優(yōu)先級
電話竊聽器
- 電話狀態(tài):空閑、響鈴、接聽
- 獲取電話管理器,設(shè)置偵聽
- 偵聽對象的實(shí)現(xiàn)
廣播接收者
- 現(xiàn)實(shí)中:電臺要發(fā)布消息,通過廣播把消息廣播出去,使用收音機(jī),就可以收聽廣播,得知這條消息
- Android中:系統(tǒng)在運(yùn)行過程中,會產(chǎn)生會多事件,那么某些事件產(chǎn)生時,比如:電量改變、收發(fā)短信、撥打電話、屏幕解鎖、開機(jī),系統(tǒng)會發(fā)送廣播,只要應(yīng)用程序接收到這條廣播,就知道系統(tǒng)發(fā)生了相應(yīng)的事件,從而執(zhí)行相應(yīng)的代碼。使用廣播接收者,就可以收聽廣播
創(chuàng)建廣播接收者
1、 定義java類繼承BroadcastReceiver
2、 在清單文件中定義receiver節(jié)點(diǎn),定義name屬性,指定廣播接收者java類的全類名
3、 在intent-filter的節(jié)點(diǎn)中,指定action子節(jié)點(diǎn),action的值必須跟要接受的廣播中的action匹配,比如,如果要接受打電話廣播,
那么action的值必須指定為
- 因?yàn)榇螂娫拸V播中所包含的action,就是”android.intent.action.NEW_OUTGOING_CALL”,所以我們定義廣播接收者時,
action必須與其匹配,才能收到這條廣播 - 即便廣播接收者所在進(jìn)程已經(jīng)被關(guān)閉,當(dāng)系統(tǒng)發(fā)出的廣播中的action跟該廣播接收者的action匹配時,系統(tǒng)會啟動該廣播接收者所在的進(jìn)程,
并把廣播發(fā)給該廣播接收者
短信防火墻
- 系統(tǒng)發(fā)送短信廣播時,是怎么把短信內(nèi)容存入廣播的,我們就只能怎么取出來
- 如果短信過長,那么發(fā)送時會拆分成多條短信發(fā)送,那么短信廣播中就會包含多條短信
- 4.0之后,廣播接收者所在進(jìn)程如果從來沒啟動過,那么廣播接收者不會生效
- 4.0之后,如果系統(tǒng)自動關(guān)閉廣播接收者所在進(jìn)程,在廣播中的action跟該廣播接收者的action匹配時,系統(tǒng)會啟動該廣播接收者所在的進(jìn)程,但是如果是用戶手動關(guān)閉該進(jìn)程,
那么該進(jìn)程會進(jìn)入凍結(jié)狀態(tài),再也不會啟動了,直到用戶下一次手動啟動該進(jìn)程
廣播的分類
無序廣播
- 所有與廣播中的action匹配的廣播接收者都可以收到這條廣播,并且是沒有先后順序,視為同時收到
有序廣播
- 所有與廣播中的action匹配的廣播接收者都可以收到這條廣播,但是是有先后順序的,按照廣播接收者的優(yōu)先級排序
服務(wù)
- Service
- 運(yùn)行于后臺的一個組件,用來運(yùn)行適合運(yùn)行在后臺的代碼,服務(wù)是沒有前臺界面,可以視為沒有界面的activity
進(jìn)程優(yōu)先級
電話錄音機(jī)
電話的狀態(tài)
- 空閑狀態(tài)
- 響鈴狀態(tài)
- 摘機(jī)狀態(tài)
錄音機(jī)
- 音頻文件的編碼和格式不是一一對應(yīng)的
案例3:監(jiān)聽SD卡狀態(tài)
public class SDStatusReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//判斷收到的到底是什么廣播String action = intent.getAction();if("android.intent.action.MEDIA_MOUNTED".equals(action)){Toast.makeText(context, "SD卡可用", 0).show();}else if("android.intent.action.MEDIA_REMOVED".equals(action)){Toast.makeText(context, "SD卡拔出", 0).show();}else if("android.intent.action.MEDIA_UNMOUNTED".equals(action)){Toast.makeText(context, "SD卡不可用", 0).show();}}}案例4:手機(jī)勒索軟件
public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 啟動Activity,實(shí)現(xiàn)開機(jī)自動啟動勒索軟件Intent it = new Intent(context, MainActivity.class);//創(chuàng)建任務(wù)棧存放啟動的Activityit.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(it);}}案例5:監(jiān)控應(yīng)用的狀態(tài)
public class APPStatusReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubString action = intent.getAction();Uri uri = intent.getData();if("android.intent.action.PACKAGE_ADDED".equals(action)){Toast.makeText(context, uri.toString() + "被安裝了", 0).show();}if("android.intent.action.PACKAGE_REPLACED".equals(action)){Toast.makeText(context, uri.toString() + "被升級了", 0).show();}if("android.intent.action.PACKAGE_REMOVED".equals(action)){Toast.makeText(context, uri.toString() + "被卸載了", 0).show();}}}案例6:發(fā)送自定義廣播
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){//發(fā)送自定義廣播Intent intent = new Intent();//廣播中的action也是自定義的intent.setAction("com.itheima.zdy");sendBroadcast(intent);}}案例7:電話錄音機(jī)
public class RecorderService extends Service {private MediaRecorder recorder;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();//拿到電話管理器TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);//監(jiān)聽電話狀態(tài)//events:決定PhoneStateListener偵聽什么內(nèi)容tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);}class MyListener extends PhoneStateListener{//一旦電話狀態(tài)改變,此方法調(diào)用@Overridepublic void onCallStateChanged(int state, String incomingNumber) {// TODO Auto-generated method stubsuper.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_IDLE:System.out.println("空閑");if(recorder != null){recorder.stop();recorder.release();recorder = null;}break;case TelephonyManager.CALL_STATE_RINGING:System.out.println("響鈴");if(recorder == null){recorder = new MediaRecorder();recorder.setAudioSource(MediaRecorder.AudioSource.MIC);recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setOutputFile("sdcard/luyin.3gp");recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);try {recorder.prepare();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}break;case TelephonyManager.CALL_STATE_OFFHOOK:System.out.println("摘機(jī)");//開始錄音if(recorder != null){recorder.start();}break;}}}} public class BootReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//啟動錄音機(jī)服務(wù)Intent it = new Intent(context, RecorderService.class);context.startService(it);}} public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){Intent intent = new Intent(this, RecorderService.class);startService(intent);} }攔截短信的廣播
private class InnerSmsReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("InnerSmsReceiver");// 獲取到短信Object[] objects = (Object[]) intent.getExtras().get("pdus");for (Object obj : objects) {SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);// 獲取到短信內(nèi)容String body = smsMessage.getMessageBody();// 獲取到電話號碼String phone = smsMessage.getDisplayOriginatingAddress();// 根據(jù)電話號碼查詢攔截的模式String mode = dao.findNumberMode(phone);/*** 黑名單的攔截模式1 全部攔截(電話攔截+ 短信攔截) 2 電話攔截3 短信攔截*/if ("1".equals(mode) || "3".equals(mode)) {System.out.println("被哥攔截了");//往短信攔截數(shù)據(jù)庫里面添加數(shù)據(jù)abortBroadcast();}/*** 根據(jù)內(nèi)容攔截(智能攔截)*/if (body.contains("xue sheng mei")) {System.out.println("學(xué)生妹被攔截了");abortBroadcast();}}} }注冊靜態(tài)廣播
receiver = new InnerSmsReceiver(); IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED"); // 設(shè)置優(yōu)先級 filter.setPriority(2147483647); // 注冊一個短信監(jiān)聽的廣播 registerReceiver(receiver, filter);反注冊廣播,防止內(nèi)存泄露
public void onDestroy() {super.onDestroy();// 反注冊unregisterReceiver(receiver);receiver = null;// 當(dāng)不用了。設(shè)置為nullmTelephonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);listener = null; }注冊廣播并設(shè)置優(yōu)先級
<!-- 攔截黑名單信息--> <receiver android:name="com.itheima.mobilesafe_sh2.receiver.InnerSmsReceiver " ><intent-filter android:priority="1000" ><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter> </receiver>總結(jié)
以上是生活随笔為你收集整理的Android应用开发-广播和服务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android应用开发:动画和Fragm
- 下一篇: 自定义组合控件