Broadcast(广播)是Android系统四大组件之一,Broadcast的主要作用是接收系统或者自定义的广播,并进行相关的处理工作。在广播中的操作时间不能太长,超过5s将被系统回收,造成ANR;如果需要在onReceive方法中做复杂的业务处理,最好的方法是开启一个线程来处理。
接收广播的方式有两种:一是通过代码注册接收广播;二是通过xml配置的方式接收广播。
两种注册广播功能的区别:
代码注册的方式必须是该应用的进程已经启动,并且注册该广播的Activity或者Service等已经被实例化,才能接收该注册的广播;
xml配置注册广播则不需要以上的各种限制,只要系统发送了广播,就能接收到注册的广播。
在实际应用中,如果想要监听系统发出的广播,在接收到广播后做出相应的逻辑操作。如果选择代码方式注册广播,就会导致一系列问题,因为可能在系统发出广播的时候,该应用的进程并没有启动,导致应用接收不到广播,逻辑操作不能执行的问题。因此建议选择xml的方式注册广播。同时,如果大量使用XML注册广播,会降低系统性能,所以在选择广播注册方式时,应该根据具体业务需求,选择最适合的注册方式。
一、代码方式注册广播
(1)设置广播过滤器——需要接收的广播
//系统发出Intent.ACTION_MEDIA_MOUNTED的时候注册了scheme //因此在注册监听广播的时候IntentFilter必须添加相应的Scheme才能接收相应的广播 // 接收SDCard mount(安装)广播 IntentFilter mMountFilter= new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); //需要添加Scheme mMountFilter.addDataScheme("file");
(2)声明广播接收器——注册广播信息
// 注册广播监听 registerReceiver(mReceiver, mMountFilter);
监听SDcard安装(Mounted)广播的具体代码如下(MainActivity.java):
package com.jony.broadcast; import android.os.Bundle; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; import android.widget.Toast; public class MainActivity extends Activity { private IntentFilter mMountFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // do your logic System.out.println("SDcard is mounted"); Toast.makeText(MainActivity.this, "SDcard have mounted", Toast.LENGTH_LONG).show(); } }; protected void onStart() { super.onStart(); //系统发出Intent.ACTION_MEDIA_MOUNTED的时候注册了scheme //因此在注册监听广播的时候IntentFilter必须添加相应的Scheme才能接收相应的广播 mMountFilter.addDataScheme("file"); registerReceiver(mReceiver, mMountFilter);//注册广播监听 }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onStop() { super.onStop(); unregisterReceiver(mReceiver);// 取消广播监听 } }
Manifest.xml文件比较简单,在此不再给出源码
二、XML方式注册广播
继承BroadcastReceiver类,实现onReceive方法——该方法中实现相应的业务逻辑即可
MyBroadcasrReceiver代码如下(MyBroadcasrReceiver.java)
package com.jony.broadcast.broadcast_sticky_test; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class MyBroadcasrReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // do your logic System.out.println("BroadcasrReceiver is starting"); Toast.makeText(context, "BroadcasrReceiver is starting", Toast.LENGTH_LONG).show(); } }
在XML中配置自定义BroadcastReceiver的action以及相应的data,在Mainfest中进行如下定义:
<receiver android:name=".MyBroadcasrReceiver" android:label="@string/receiver"> <intent-filter> <action android:name="com.jony.normalbroadcast"/> <data android:scheme="file"/> </intent-filter> <intent-filter> <action android:name="com.jony.stickybroadcast"/> </intent-filter> </receiver>
小节:以上两种接收广播的方式各有优点,具体选择哪种方式监听广播,需要更具业务需求,做出相应的选择。
首先通过继承BroadcastReceiver类,实现onReceive方法——该方法中实现相应的业务逻辑即可
MyBroadcasrReceiver代码如下(MyBroadcasrReceiver.java)
package com.jony.broadcast.broadcast_sticky_test; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast; public class MyBroadcasrReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // do your logic System.out.println("BroadcasrReceiver is starting"); Toast.makeText(context, "BroadcasrReceiver is starting", Toast.LENGTH_LONG).show(); } }
在XML中配置自定义BroadcastReceiver的action以及相应的data,在Mainfest中进行如下定义:
<receiver android:name=".MyBroadcasrReceiver" android:label="@string/receiver"> <intent-filter> <action android:name="com.jony.normalbroadcast"/> <data android:scheme="file"/> </intent-filter> <intent-filter> <action android:name="com.jony.stickybroadcast"/> </intent-filter> </receiver>
实现BroadcasrReceiver的子类并在Mainfest中进行了以上配置之后,接下来就是见证奇迹的时候了,看看我们怎样启动我们自定义的Broadcast吧……
启动广播的步骤大致可以分为两步:
第一步注册我们自定义的广播;
第二部发送相应的Action——即我们在Mainfest中配置<receiver>时设置的相应action
代码如下所示(MainActivity.java):
package com.jony.broadcast.broadcast_sticky_test; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.content.IntentFilter; import android.view.Menu; public class MainActivity extends Activity { private IntentFilter mFilter; private MyBroadcasrReceiver mReceiver = new MyBroadcasrReceiver(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFilter = new IntentFilter(); mFilter.addAction("com.jony.normalbroadcast"); // 注册广播 registerReceiver(mReceiver, mFilter);// 在XML中进行广播注册 Intent intent = new Intent("com.jony.stickybroadcast"); sendBroadcast(intent);// 发送广播 } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver); } }
StickyBroadcast一般很少用到,但是千万不要忘记小人物也有大用处,所以请尊重身边的每一个人。闲话少说,直接切入正题,在使用代码注册广播(广播被嵌入到Activity中或者是Service中)时,当发送一个广播时,被嵌入的Activity或者Service还没有被启动时,发送的normal广播是接收不到的,这时只有发送sticky广播,在应用程序启动被嵌入广播的Activity或者Service时,会接收到stick广播,因此在这样的业务中stick广播就派上了用处。
举例说明:
在使用sticky广播时,需要在AndroidManifest.xml中赋予发送sticky广播的权限
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
首先在被嵌入的Activity中注册广播,具体代码如下(SecondActivity.java):
package com.jony.broadcast.broadcast_sticky_test; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.widget.Toast; public class SecondActivity extends Activity{ private IntentFilter filter; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, intent.getAction(), Toast.LENGTH_LONG).show(); } }; protected void onResume() { super.onResume(); }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); filter = new IntentFilter(); filter.addAction("com.jony.normalbroadcast"); filter.addAction("com.jony.stickybroadcast"); registerReceiver(mReceiver, filter); } @Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver); } }
在MainActivity中发送广播,代码如下所示(MainActivity.java):
package com.jony.broadcast.broadcast_sticky_test; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { private Button normal_button,sticky_button,launch_button; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init_data(); } private void init_data() { normal_button = (Button) findViewById(R.id.send_normal_broadcast); sticky_button = (Button) findViewById(R.id.send_sticky_broadcast); launch_button = (Button) findViewById(R.id.receive_broadcast); normal_button.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.jony.normalbroadcast"); sendBroadcast(intent); } }); sticky_button.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction("com.jony.stickybroadcast"); sendStickyBroadcast(intent); } }); launch_button.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), SecondActivity.class); startActivity(intent); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onPause() { super.onPause(); } }
布局文件和Manifest配置文件都比较简单,在此不再给出。
最后,见证奇迹的时刻就交给大家了……