Android开发历程_14(广播机制)
广播机制按照字面理解就是广于播之,在计算机网络中这个词比较常见,它的意思是说发送端把信息发送出去,是以广播的方式发送出去,该信息可以同时被多个接收端介绍,当然接收端也可以不接收,另外接收端介绍到这信息后怎么处理广播的发送端也是不用考虑的。因此广播机制还是挺有用的,利用广播信息可以为触发的一些事件发送消息。Android中的广播机制可以参考mars老师的这张图片:
如图所示,有多个广播接收者在android中注册过,当一个事件产生后,它可以发送一个广播信息,然后这些接收者来接收该信息。广播接收者的实现一般是写成一个类,该类继承android提供的类BroadcastReceiver,并且我们需要复写该类的onCreate方法,因为我们需要在该方法中实现接收到信息后的处理过程。
下面通过2个简单的例子来学会怎样在andorid中使用广播信息,其实在文章Android开发历程_13(Service的使用)中已经使用过广播机制,即在servier下发送广播信息,主activity中接收该信息来更新UI。在那个程序中使用的是intentFilter这个类,然后在activity中使用registerReceiver函数来发送广播信息,这些代码的实现都是在java语句中实现。这是第一种注册广播消息的方法,另外一种方法是在AndroidMainifest.xml文件中注册。下面2个例子就分别介绍了这2中方法。
在介绍这2个例子之前,我们先来看看这2种注册方法的去别:
1. 在Manifest.xml文件中注册的话,因为需要一个android:name设置,所以我们继承BroadcastReceiver的类需要单独作为一个类文件出现,而在java代码中注册,我们可以使用一个内部类就可以了。
2. 在Mainfest.xml文件中注册过的BroadcastReceiver,即使我们对应的程序已经关闭,但是只要我们的系统(比如说手机,平板)开启,这该BroadcastReceiver依然处于活动状态,依然可以接受到广播信息。
3. 如果我们需要实时监测某个广播信息,则可以采用在Mainfest.xml中进行注册,但如果我们用广播信息来更新activity的UI,则应该采用在java代码中进行注册。
例一:
采用在AndroidMainifest.xml文件中注册BroadcastReceiver。
首先发送端还是先建立一个intent,然后采用intent的setAction方法设置接收器的action类型,最后在activity中启动broadcast,即使用函数sendBroadcast(intent)。
实验说明:
在com.example.broadcast1包下新建一个TestReceiver类,该类继承BroadcastReceiver,继承的这个类的对象的生命周期只有在其接受到了广播信息的时候才存在,当其接受完了广播信息且处理完信息内容后,该对象也就结束了。如果下次又有广播信息被接受,则该对象又重新启动一遍。 同时,我们在TestReceiver这个类的构造函数中打印"TestReceiver"语句,在onReceive方法中打印"OnReceiver"信息。
主界面中有一个按钮,按钮按下时就发生广播消息。主界面启动时打印"onCreate"。
下面是当按下一次start按钮后的输出信息:
由此可见,广播信息被接受成功了。
实验主要代码及注释(附录有实验工程code下载链接):
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.broadcast1" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".TestReceiver"> <intent-filter> <action android:name="android.intent.action.EDIT"/> </intent-filter> </receiver> </application> </manifest>
MainActivity.java:
package com.example.broadcast1; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Button start = null; private TextView text = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println("onCreate"); start = (Button)findViewById(R.id.start); start.setOnClickListener(new MyStartOnClickListener()); text = (TextView)findViewById(R.id.text); } public class MyStartOnClickListener implements OnClickListener { public void onClick(View arg0) { // TODO Auto-generated method stub // TestReceiver tr = new TestReceiver(); Intent intent = new Intent();//采用intent发送数据 intent.setAction(Intent.ACTION_EDIT);//只发送给action为ACTION_EDIT的对象 MainActivity.this.sendBroadcast(intent);//通过广播方式发送该intent,只有特定 //action的接收者才能收到该广播信息 } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
TestReceiver.java:
package com.example.broadcast1; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Button; import android.widget.TextView; import com.example.broadcast1.R; public class TestReceiver extends BroadcastReceiver{ private Button start = null; private TextView text = null; public TestReceiver() { System.out.println("TestReceiver"); } @Override public void onReceive(Context arg0, Intent arg1) { System.out.println("OnReceiver"); } }
例二:
这个例子主要是学习在java代码中注册broadcastReceiver,通过接收一个发送短信的广播,顺便学习下在android中跟发送和接收短信有关的操作.
实验说明
和上面例子一样,我们同样写一个类,该类继承BroadcastReceiver,在该类的onReceive方法中读取接收到的短信内容,并将短信内容打印到后台。在主activity中我们注册一个广播接收器,设置的action过滤为"android.provider.Telephony.SMS_RECEIVED",即只有具备该action的广播接收器才能给接收到短信。发送短信采用的是DDMS来模拟的,即该短信的发送是由另外的程序执行的,我们也可以理解为系统发出,因此广播信息的发送在这个例子中不用我们用代码来实现。DDMS发送出来的短信息是通过intent发送的,intent里面就自带了名为"android.provider.Telephony.SMS_RECEIVED"的action,所以我们的接收器中intent过滤器中也是设置的该aciton,因此是可以收到短信的。
要使自己写的android程序能够收到短信息来临的广播,则不管是在java程序中注册broadcastReceiver还是在manifest.xml中注册,在manifest.xml文件中必须添加一句代码:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>并且该代码是和application平级的,也就是说是manifest的直接子标签.如果没有改句,即使程序中注册过广播接收,同样也收不到短信的。
用broadcastReceiver读取短信内容的代码基本上可以固定,在onReceive()方法中实现的,代码如下:
单击一次Start Broadcast按钮后,在DDMS中发送一条消息,然后再单击Stop Broadcast按钮后的,后台显示如下:
实验主要部分代码(附录有实验工程code下载链接):
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.broadcast2" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/title_activity_main" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".SMSReceiver"> <!-- <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> </intent-filter> --> </receiver> </application> </manifest>
MainActivity.java:
package com.example.broadcast2; import android.app.Activity; import android.content.IntentFilter; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button start = null; private Button stop = null; private SMSReceiver sms_receiver = null; private static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); start = (Button)findViewById(R.id.start_broadcast); start.setOnClickListener(new StartOnClickListener()); stop = (Button)findViewById(R.id.stop_broadcast); stop.setOnClickListener(new StopOnClickListener()); } class StartOnClickListener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub sms_receiver = new SMSReceiver(); IntentFilter intent_filter = new IntentFilter(); intent_filter.addAction(SMS_ACTION); MainActivity.this.registerReceiver(sms_receiver, intent_filter); System.out.println("Start Broadcast!"); } } class StopOnClickListener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub MainActivity.this.unregisterReceiver(sms_receiver); System.out.println("Stop Broadcast!"); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
SMSReceiver.java:
package com.example.broadcast2; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub System.out.println("receive message"); //获得intent中的bundle Bundle bundle = intent.getExtras(); //该bundle中有个名为“pdus”的键值对 Object[] myOBJpdus = (Object[])bundle.get("pdus"); //新建一个SmsMessage数组,用于存储消息内容的 SmsMessage[] messages = new SmsMessage[myOBJpdus.length]; System.out.println(messages.length);//一条短信的长度为1 for(int i = 0; i < messages.length; i++) { //输入内容到messages数组 messages[i] = SmsMessage.createFromPdu((byte[])myOBJpdus[i]); System.out.println(messages[i].getDisplayMessageBody()); } } }
activity_main.xml:
<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" > <Button android:id="@+id/stop_broadcast" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/stop_broadcast" android:layout_alignParentBottom="true" /> <Button android:id="@+id/start_broadcast" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/start_broadcast" android:layout_above="@id/stop_broadcast" /> </RelativeLayout>
总结:android中的广播机制可以由2种方法来注册,每种方法的应用领域不同,我们应该根据我们的需求来选择。
参考资料:
http://www.mars-droid.com/bbs/forum.php
附录: