Android基本组件之BroadcastReceiver
BroadcastReceiver基本概念
在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对程序中发送出来的Broadcast进行过滤接受并响应的一类组件。
如何使用BroadcastReceiver
1.首先在需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用 sendOrderBroadcast()、sendStickyBroadcast()方法或者sendBroadcast()方法,把 Intent对象以广播方式发送出去。
2.当Intent发送以后,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。所以当我们定义一个BroadcastReceiver的时候,都需要实现onReceive()方法。
如何使用BroadcastReceiver
1.首先在需要发送信息的地方,把要发送的信息和用于过滤的信息(如Action、Category)装入一个Intent对象,然后通过调用 sendOrderBroadcast()、sendStickyBroadcast()方法或者sendBroadcast()方法,把 Intent对象以广播方式发送出去。
2.当Intent发送以后,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。所以当我们定义一个BroadcastReceiver的时候,都需要实现onReceive()方法。
注册BroadcastReceiver有两种方式:
静态注册:在AndroidManifest.xml中用标签生命注册,并在标签内用标签设置过滤器。
<receiver android:name="myRecevice"> //继承BroadcastReceiver,重写onReceiver方法
<intent-filter>
<action android:name="com.dragon.net"></action> //使用过滤器,接收指定action广播
</intent-filter>
</receiver>
上面的xml文件中在AndroidManifest.xml中注册了一个名为myRecevice的继承BroadcastReceiver的类,它的过滤器定义在<intent-filter.../>标签中。
动态注册:在代码中实例化一个继承BroadcastReceiver的类,并实例化过滤器,通过Activity的静态方法registerReceiver()注册。
myReceiver = new MyReceiver(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(String); //为BroadcastReceiver指定action,使之用于接收同action的广播
registerReceiver(myReceiver,intentFilter);
下面这段代码是动态注册方法的演示:
package com.example.receiverdemo; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Intent; import android.content.IntentFilter; public class ReceiverActivity extends Activity { private Button bind; private Button sent; private Button unbind; private MyReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_receiver); bind = (Button)findViewById(R.id.bind); sent = (Button)findViewById(R.id.sent); unbind = (Button)findViewById(R.id.unbind); receiver = new MyReceiver(this); bind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction("qwerty"); registerReceiver(receiver, intentfilter); } }); sent.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction("qwerty"); intent.putExtra("msg", "耗子"); sendBroadcast(intent); } }); unbind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unregisterReceiver(receiver); } }); } }
注1:对于动态注册receiver而言,一般情况下最好是在onResume方法中注册,在onPause方法中取消注册。
之所以要这样,是因为这样可以减少Android程序的内存使用。只有在Activity运行的时候我们才注册receiver,而当Activity失去焦点的时候我们就取消了注册。(如果不理解,可以参看Activity的生命周期图)。
注2:BroadcastReciver对象的生命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报错 。
每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕, Android 会认为该程序无响应 . 所以在BroadcastReceiver 里不能做一些比较耗时的操作 , 否侧会弹出 ANR(Application No Response) 的对话框。
怎么用好 BroadcastReceiver :
如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由 Service 来完成 。这里不能使用子线程来解决 , 因为 BroadcastReceiver 的生命周期很短 , 子线程可能还没有结束BroadcastReceiver 就先结束了 。BroadcastReceiver 一旦结束 , 此时 BroadcastReceiver 的所在进程很容易在系统需要内存时被优先杀死 。因为它属于空进程 ( 没有任何活动组件的进程 )。如果它的宿主进程被杀死 ,那么正在工作的子线程也会被杀死 。所以采用子线程来解决是不可靠的 。
进一步的补充:
Broadcast 类型
在本文中我们暂时只介绍两种Broadcast
1.Normal Broadcast 普通广播
发送这种广播,能够在同一时刻(逻辑上)被所有的注册的接收者收到,它的效率比较高。
缺点:不能将结果传递给下一个接受者,而且不能终止Broadcast Intent的传播。
在Activity中通过静态方法sendBroadcast()方法发送。
2.Ordered Broadcast 有序广播
接收者将按照预想声明的优先级一次接收Broadcast。优先级声明在<intent-filter .../>的android:priority属性中,也可以在代码中调用IntentFilter的setPriority()方法进行设置。优先级的取值范围为-1000~1000,数值越大优先级越高。
通过接收者setResultExtras()将结果传递给下一个接受者,通过abrotBroadcast()方法终止Broadcast的继续传播。下一个接收者通过getResultExtras()方法获取上一个接收者的结果。
在Activity中通过静态方法sendOrderedBroadcast()方法发送。
下面这段代码演示不同优先级别的receiver的接收情况:
package com.example.receiverdemo; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import android.content.Intent; import android.content.IntentFilter; public class ReceiverActivity extends Activity { private Button bind; private Button sent; private Button unbind; private MyReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_receiver); bind = (Button)findViewById(R.id.bind); sent = (Button)findViewById(R.id.sent); unbind = (Button)findViewById(R.id.unbind); receiver = new MyReceiver(this); bind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction("qwerty"); intentfilter.setPriority(999); registerReceiver(receiver, intentfilter); } }); sent.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction("qwerty"); intent.putExtra("msg", "耗子"); sendOrderedBroadcast(intent, null); } }); unbind.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unregisterReceiver(receiver); } }); } }
package com.example.receiverdemo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.widget.Toast; public class MyReceiver extends BroadcastReceiver { private Context context; public MyReceiver(Context context) { this.context = context; } @Override public void onReceive(Context context, Intent intent) { String msg = intent.getStringExtra("msg"); Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); Bundle extras = new Bundle(); extras.putString("test", "mouse"); setResultExtras(extras); } }
package com.example.receiverdemo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.widget.Toast; public class MyReceiver1 extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle bundle = getResultExtras(true); String text = bundle.getString("test"); String msg = intent.getStringExtra("msg"); Toast.makeText(context, msg+text, Toast.LENGTH_SHORT).show(); abortBroadcast(); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.receiverdemo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.receiverdemo.ReceiverActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name = "com.example.receiverdemo.MyReceiver1"> <intent-filter android:priority="0"> <action android:name="qwerty"/> </intent-filter> </receiver> </application> </manifest>
<LinearLayout 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:orientation="vertical" > <Button android:id="@+id/bind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="注册" /> <Button android:id="@+id/sent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="发送" /> <Button android:id="@+id/unbind" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="注销" /> </LinearLayout>