Android Broadcast 廣播
進程內本地廣播
如果你是在你的應用之內使用廣播,即不需要跨進程,考慮使用LocalBroadcastManager
,這樣更有效率(因為不需要跨進程通信),並且你不用考慮一些其他應用可以發送或接收你的廣播相關的安全問題。
下面介紹更一般的方法。
廣播的兩種注冊方法
廣播有靜態和動態兩種注冊方法:
靜態注冊:在AndroidManifest.xml中加上<receiver>
標簽。
動態注冊:通過 Context.registerReceiver()
方法進行注冊。比如在onResume中注冊,在onPause中注銷。
附上例子(例子中的布局、MyReceiver類,常量類都是相同的,在前面列出):
布局文件都一樣:
<RelativeLayout 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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".DemoBroadcastActivity" > <TextView android:id="@+id/helloText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <Button android:id="@+id/sendBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/helloText" android:text="@string/send" /> </RelativeLayout>
自己寫的Receiver類:
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.Toast; public class MyReceiver extends BroadcastReceiver { public MyReceiver() { super(); Log.d(AppConstants.LOG_TAG, "Receiver constructor"); } @Override public void onReceive(Context context, Intent intent) { Log.d(AppConstants.LOG_TAG, "onReceive"); String message = intent.getStringExtra(AppConstants.MSG_KEY); Log.i(AppConstants.LOG_TAG, message); Toast.makeText(context, "Received! msg: " + message, Toast.LENGTH_SHORT).show(); } }
應用常量:
public class AppConstants { public static final String LOG_TAG = "Broadcast"; public static final String MSG_KEY = "msg"; public static final String BROADCAST_ACTION ="com.example.demobroadcast.BroadcastAction"; }
下面就是不同的部分了!
靜態注冊的實例代碼:
靜態注冊是在manifest文件中進行:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.demobroadcast" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.SEND_SMS" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.demobroadcast.DemoBroadcastActivity" android:label="@string/app_name" > <intent-filter android:priority="1000"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name="com.example.demobroadcast.MyReceiver"> <intent-filter > <action android:name="com.example.demobroadcast.BroadcastAction" /> </intent-filter> </receiver> </application> </manifest>
所以Java代碼:
package com.example.demobroadcast; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import android.app.Activity; import android.content.Intent; public class DemoBroadcastActivity extends Activity { private Button sendBtn = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo_broadcast); sendBtn = (Button) findViewById(R.id.sendBtn); sendBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(AppConstants.BROADCAST_ACTION); intent.putExtra("msg", "聖騎士wind"); sendBroadcast(intent); } }); } }
動態注冊的實例代碼:
動態注冊是在Java代碼中進行:
package com.example.demobroadcast2; import com.example.demobroadcast.R; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import android.app.Activity; import android.content.Intent; import android.content.IntentFilter; public class DemoBroadcastActivity extends Activity { private Button sendBtn = null; private MyReceiver mReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo_broadcast); sendBtn = (Button) findViewById(R.id.sendBtn); sendBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(AppConstants.BROADCAST_ACTION); intent.putExtra("msg", "聖騎士wind"); sendBroadcast(intent); } }); } @Override protected void onResume() { super.onResume(); mReceiver = new MyReceiver(); IntentFilter intentFilter= new IntentFilter(AppConstants.BROADCAST_ACTION); registerReceiver(mReceiver, intentFilter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver); } @Override protected void onDestroy() { super.onDestroy(); } }
所以Manifest文件中不需要添加標簽,正常就行。
兩種廣播
Normal broadcasts
通過 Context.sendBroadcast
發送,完全是異步的(asynchronous)。所有的接收器以不確定的順序運行,通常是同時。
這樣更有效率,但是也意味着接收器不能傳遞結果,也不能退出廣播。
Ordered broadcasts
通過 Context.sendOrderedBroadcast
發送。一次只向一個接收器發送。
由於每個接收器按順序執行,它可以向下一個接收器傳遞結果,也可以退出廣播不再傳遞給其他接收器。
接收器運行的順序可以通過 android:priority
屬性來控制,相同優先級的接收器將會以隨機的順序運行。
接收器的生命周期
一個BroadcastReceiver的對象只在 onReceive(Context, Intent)
被調用的期間有效,一旦從這個方法返回,系統就認為這個對象結束了,不再活躍。
這對你在onReceive中能做什么有很大的影響:不能做任何需要的操作(anything that requires asynchronous operation is not available)。
因為你需要從方法返回去進行你的異步操作,而返回時BroadcastReceiver的對象已經不再活躍了,系統可以(在異步操作完成前)任意殺死它的進程。
特別地,不可以在BroadcastReceiver中顯示對話框或者綁定一個service,前者應該用 NotificationManager
,后者應該用Context.startService()。
參考資料
官方文檔BroadcastReceiver:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
LocalBroadcastManager:
http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
Training: Manipulating Broadcast Receivers On Demand
http://developer.android.com/training/monitoring-device-state/manifest-receivers.html
receiver標簽
http://developer.android.com/guide/topics/manifest/receiver-element.html