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" ><TextViewandroid:id="@+id/helloText"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world" /><Buttonandroid: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");}@Overridepublic 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-sdkandroid:minSdkVersion="8"android:targetSdkVersion="17" /><uses-permission android:name="android.permission.RECEIVE_SMS" /><uses-permission android:name="android.permission.SEND_SMS" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid: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><receiverandroid: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;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_demo_broadcast);sendBtn = (Button) findViewById(R.id.sendBtn);sendBtn.setOnClickListener(new OnClickListener(){@Overridepublic 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;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_demo_broadcast);sendBtn = (Button) findViewById(R.id.sendBtn);sendBtn.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){Intent intent = new Intent();intent.setAction(AppConstants.BROADCAST_ACTION);intent.putExtra("msg", "圣骑士wind");sendBroadcast(intent);}});}@Overrideprotected void onResume(){super.onResume();mReceiver = new MyReceiver();IntentFilter intentFilter= new IntentFilter(AppConstants.BROADCAST_ACTION);registerReceiver(mReceiver, intentFilter);}@Overrideprotected void onPause(){super.onPause();unregisterReceiver(mReceiver);}@Overrideprotected 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