Android Service 服務(二)—— BroadcastReceiver
一、 BroadcastReceiver簡介
BroadcastReceiver,用於非同步接收廣播Intent,廣播Intent是通過呼叫Context.sendBroadcast()傳送、BroadcastReceiver()接收。
廣播Intent的傳送是通過呼叫Context.sendBroadcast()、Context.sendOrderedBroadcast()、Context.sendStickyBroadcast()來實現的。通常一個廣播Intent可以被訂閱了此Intent的多個廣播接收者所接收,廣播接收者和JMS中的Topic訊息接收者很相似。
廣播接收器只能接收廣播,對廣播的通知做出反應,很多廣播都產生於系統程式碼,如:時區改變的通知、電池電量不足、使用者改變了語言偏好,或者開機啟動等
廣播接收器沒有使用者介面,但是它可以為它們接收到資訊啟動一個Activity或者使用NotificationManager來通知使用者.
BroadcastReceiver 接收廣播方式:
1. Normal broadcasts(正常廣播),用 Context.sendBroadcast()傳送是完全非同步的,它們都執行在一個未定義的順序,通常是在同一時間。這樣會更有效,但意味著receiver不能包含所要使用的結果或中止的API。
2. Ordered broadcasts(有序廣播),用 Context.sendOrderedBroadcast()傳送每次被髮送到一個receiver。所謂有序,就是每個receiver執行後可以傳播到下一個receiver,也可以完全中止傳播——不傳播給其他receiver。 而receiver執行的順序可以通過matched intent-filter 裡面的android:priority來控制,當priority優先順序相同的時候,Receiver以任意的順序執行。
二、 BroadcastReceiver註冊方式
AndroidManifest.xml中,application裡面,定義receiver並設定要接收的action
- <receiver android:name=".receiver.MusicReceiver" >
- <intent-filter>
- <action android:name="com.homer.receiver.musicReceiver" />
- </intent-filter>
- </receiver>
2 動態註冊
Activity中,需在onStart()中呼叫registerReceiver()進行註冊和在onStop中呼叫unregisterReceiver()釋放服務
- private MusicReceiver receiver;
- @Override
- protected void onStart(){
- super.onStart();
- receiver = new MusicReceiver();
- IntentFilter filter = new IntentFilter();
- filter.addAction("com.homer.receiver.musicReceiver");
- this.registerReceiver(receiver, filter);
- }
- @Override
- protected void onStop(){
- this.unregisterReceiver(receiver);
- super.onStop();
- }
3 兩種註冊方式的比較
靜態註冊方式,由系統來管理receiver,而且程式裡的所有receiver,可以在xml裡面一目瞭然
動態註冊方式,隱藏在程式碼中,比較難發現;需要特別注意的是,在退出程式前要記得呼叫Context.unregisterReceiver()方法。一般在activity的onStart()裡面進行註冊, onStop()裡面進行登出。官方提醒,如果在Activity.onResume()裡面註冊了,就必須在Activity.onPause()登出。
三、 BroadcastReceiver生命週期
一個BroadcastReceiver 物件只有在被呼叫onReceive(Context, Intent)的才有效,當從該函式返回後,該物件就無效的了,結束生命週期。
因此從這個特徵可以看出,在所呼叫的onReceive(Context, Intent)函式裡,不能有過於耗時的操作,不能使用執行緒來執行。對於耗時的操作,應該在startService中來完成。因為當得到其他非同步操作所返回的結果時,BroadcastReceiver 可能已經無效了。
四、 BroadcastReceiver示例
Activity
- public class PlayMusicRecevicer extends Activity implements OnClickListener {
- private Button playBtn;
- private Button stopBtn;
- private Button pauseBtn;
- private Button exitBtn;
- private Button closeBtn;
- private Intent intent;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.music_receiver);
- playBtn = (Button) findViewById(R.id.play);
- stopBtn = (Button) findViewById(R.id.stop);
- pauseBtn = (Button) findViewById(R.id.pause);
- exitBtn = (Button) findViewById(R.id.exit);
- closeBtn = (Button) findViewById(R.id.close);
- playBtn.setOnClickListener(this);
- stopBtn.setOnClickListener(this);
- pauseBtn.setOnClickListener(this);
- exitBtn.setOnClickListener(this);
- closeBtn.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- int op = -1;
- intent = new Intent("com.homer.receiver.musicReceiver");
- switch (v.getId()) {
- case R.id.play: // play music
- op = 1;
- break;
- case R.id.stop: // stop music
- op = 2;
- break;
- case R.id.pause: // pause music
- op = 3;
- break;
- case R.id.close: // close activity
- this.finish();
- break;
- case R.id.exit: // process by MusicReceiver
- op = 4;
- this.finish();
- break;
- }
- Bundle bundle = new Bundle();
- bundle.putInt("op", op);
- intent.putExtras(bundle);
- sendBroadcast(intent); // sendBroadcast
- }
- // private MusicReceiver receiver;
- //
- // @Override
- // protected void onStart(){
- // super.onStart();
- //
- // receiver = new MusicReceiver();
- // IntentFilter filter = new IntentFilter();
- // filter.addAction("com.homer.receiver.musicReceiver");
- // this.registerReceiver(receiver, filter);
- // }
- //
- // @Override
- // protected void onStop(){
- // this.unregisterReceiver(receiver);
- //
- // super.onStop();
- // }
- @Override
- public void onDestroy(){
- super.onDestroy();
- if(intent != null){
- stopService(intent);
- }
- }
- }
BroadcastReceiver
- public class MusicReceiver extends BroadcastReceiver { // receive Broadcast
- @Override
- public void onReceive(Context context, Intent intent) {
- if(intent != null){
- Bundle bundle = intent.getExtras();
- Intent it = new Intent(context, MusicReceiverService.class); // call service for MusicReceiverService.class
- it.putExtras(bundle);
- if(bundle != null){
- int op = bundle.getInt("op");
- if(op == 4){
- context.stopService(it); // stopService
- }else{
- context.startService(it); // startService
- }
- }
- }
- }
- }
Service(BroadcastReceiver呼叫的後臺服務)
- public class MusicReceiverService extends Service {
- private MediaPlayer mediaPlayer;
- @Override
- public IBinder onBind(Intent arg0) {
- return null;
- }
- @Override
- public void onCreate() {
- Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
- if (mediaPlayer == null) {
- mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
- mediaPlayer.setLooping(false);
- }
- }
- @Override
- public void onDestroy() {
- Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
- if (mediaPlayer != null) {
- mediaPlayer.stop();
- mediaPlayer.release();
- }
- }
- @Override
- public void onStart(Intent intent, int startId) {
- if (intent != null) {
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- int op = bundle.getInt("op");
- switch (op) {
- case 1:
- play();
- break;
- case 2:
- stop();
- break;
- case 3:
- pause();
- break;
- }
- }
- }
- }
- public void play() {
- if (!mediaPlayer.isPlaying()) {
- mediaPlayer.start();
- }
- }
- public void pause() {
- if (mediaPlayer != null && mediaPlayer.isPlaying()) {
- mediaPlayer.pause();
- }
- }
- public void stop() {
- if (mediaPlayer != null) {
- mediaPlayer.stop();
- try {
- mediaPlayer.prepare(); // 在呼叫stop後如果需要再次通過start進行播放,需要之前呼叫prepare函式
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
- }
- }
AndroidManifest.xml
- <service
- android:name=".receiver.MusicReceiverService"
- android:enabled="true" >
- <intent-filter>
- <action android:name="com.homer.service.musicReceiverService" />
- </intent-filter>
- </service>
- <receiver android:name=".receiver.MusicReceiver" >
- <intent-filter>
- <action android:name="com.homer.receiver.musicReceiver" />
- </intent-filter>
- </receiver>
五、程式碼解析
1、Activity中,PlayMusicService中通過重寫OnClickListener 介面onClick()方法實現對播放音樂的控制,把音樂各種操作用數字通過Intent傳遞給service
然後通過構造一個Intent , intent = new Intent("com.homer.receiver.musicReceiver");
其中,com.homer.receiver.musicReceiver是 AndroidManifest.xml 對receiver的定義(或動態註冊addAction為filter.addAction("com.homer.receiver.musicReceiver");)
2、Activity中,音樂播放的控制,利用Bundle繫結數字op後,通過 sendBroadcast(intent); 廣播出去Bundle bundle = new Bundle();
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent);
3、 BroadcastReceiver中,會處理Activity啟動的 sendBroadcast(intent); 廣播,通過實現onReceive()方法,解析Activity中Intent的Bundle資料。
然後通過Intent it = new Intent(context, MusicReceiverService.class); 初始化一個啟動Service服務的Intent
最後根據解析bundle的op數值決定啟動context.startService(it); 服務 或 關閉context.stopService(it); 服務
4、Service中,處理BroadcastReceiver廣播啟動的MusicReceiverService服務,即依次呼叫service的啟動過程:onCreate --> onStart(可多次呼叫) --> onDestroy
onCreate(), 建立mediaPlayer
onStart(), 通過獲取Bundle bundle = intent.getExtras();,提取int op = bundle.getInt("op");,然後執行響應的音樂播放操作
onDestroy(),停止並釋放mediaPlayer音樂資源,如果當執行context.stopService()時呼叫此方法
5、Activity中,onClick()函式中close與exit是執行含義是不同的:
close : 只是執行了this.finish(); 關閉了本Activity窗體,service並沒有被關掉,音樂依然會繼續在後臺播放
exit : 先呼叫了stopService(intent); 關閉了service服務,在Service中會呼叫3中的onDestroy()停止並釋放音樂資源,後才執行this.finish(); 關閉了本Activity窗體
六、BroadcastReceiver總結
BroadcastReceiver需要先註冊receriver(靜態或動態)—> 傳送廣播sendBroadcast(intent) —> 處理廣播onReceive(Context context, Intent intent) —> 啟動服務startService(it) —> 關閉服務stopService(it)
其中,receriver兩種註冊方式,靜態註冊在AndroidManifest.xml中的receiver和動態註冊在PlayMusicRecevicer註釋的程式碼部分,兩者選擇一種即可
參考推薦:
Android之BroadcastReceiver的使用(靜態和動態兩種註冊方式)
相關文章
- Android之BroadcastReceiverAndroidAST
- Android BroadcastReceiver(廣播)AndroidAST
- Android - BroadcastReceiver 廣播AndroidAST
- Android Service詳解(二)Android
- Android BroadcastReceiver使用詳解AndroidAST
- android native service編寫及兩個服務程式通訊Android
- Android入門教程 | 四大元件之Service(前臺服務,後臺服務)Android元件
- 服務網格 Service Mesh
- Android 四大元件之 BroadcastReceiverAndroid元件AST
- Android四大元件之BroadcastReceiverAndroid元件AST
- k8s Service 服務K8S
- Android 四大元件之二-------ServiceAndroid元件
- 【應用服務 App Service】App Service 新手資料包APP
- 【Azure 應用服務】Azure App Service 自帶 FTP服務APPFTP
- Android 8.0 原始碼分析 (六) BroadcastReceiver 啟動Android原始碼AST
- Android四大元件之BroadcastReceiver篇Android元件AST
- angular6自定義服務serviceAngular
- 服務網格service mesh 之 Linkerd
- Android ServiceAndroid
- Android四大元件之——BroadcastReceiver介紹Android元件AST
- 【Azure 應用服務】App Service服務無法啟動,開啟Kudu站點,App Service Editor 頁面均丟擲:The service is unavailableAPPAI
- 淺析Kubernrtes服務型別(Service Types)型別
- 物件儲存服務(Object Storage Service,OBS)物件Object
- Android Intent ServiceAndroidIntent
- Android Service SecurityAndroid
- Android點將臺:傳令官[-BroadcastReceiver-](使用級)AndroidAST
- C# Windows Service 服務程式的編寫C#Windows
- Linkerd Service Mesh 服務配置檔案規範
- 什麼是資料即服務(Data as a Service)?
- 【PDB】 為Oracle pdb新增服務(pdb add service)Oracle
- SAP Spartacus 事件服務 Event Service 使用介紹事件
- 如何使用FastReport.Service.dll建立Web服務ASTWeb
- 阿里雲Kubernetes容器服務Istio實踐之整合日誌服務Log Service阿里
- 【應用服務 App Service】 App Service Rewrite 例項 - 反向代理轉發功能APP
- Azure AD Domain Service(二)為域服務中的機器配置 Azure File Share 磁碟共享AI
- Android Service完全解析Android
- 為什麼要使用服務網格Service Mesh?
- 服務發現與負載均衡機制-Service負載
- 基於.Net Core 5.0 Worker Service 的 Quart 服務