什么是广播机制?

简单点来说,是一种广泛运用在程序之间的传输信息的一种方式。比如,手机电量不足10%,此时系统会发出一个通知,这就是运用到了广播机制。

广播机制的三要素:

Android广播机制包含三个要素:广播(Broadcast) - 用于发送广播;广播接收器(BroadcastReceiver) - 用于接收广播;意图(Intent)-用于保存广播相关信息的媒介。

可以把它理解成我们的传统电视台,我们的电视就是一个广播接收器,然而电视有很多频道,是由电视台发送出来的,也就是广播了,意图可以理解成不同频道所播放的不同电视内容。我们每次只能观看一个频道,也就是说一个广播接收器只能接受一个广播,至于如何去区分到底是哪个广播接收器接收哪个广播,这里会有个过滤器intent-filter,我们只需要去设置intent的action标示符即可(下文会提到)。

首先,先来说下广播接收器(BroadcastReceiver):

我们要使用一个广播需要先注册它,就像我们新添一个Activity一样,需要在AndroidManifest.xml里面声明,广播亦是如此。

广播接收器注册,这里提供了2种方式

1、静态注册,也就是在配置文件AndroidManifest.xml声明:

         <receiver
android:name="广播接收器所在的包名类名"
android:enabled="true"
android:process=":remote" >
<intent-filter>
<action android:name="过滤标示符,用来区分接收哪个广播" />
</intent-filter>
</receiver>

2、代码动态注册:

 //创建一个广播接受者
MyReceiver receiver = new MyReceiver();
//创建过滤器,并指定action,使之用于接收同action的广播
IntentFilter filter = new IntentFilter("过滤标示符,用来区分接收哪个广播");
//注册广播接收器
Context.registerReceiver(receiver, filter); 

通过静态方式注册的广播接收器,不需要手动注销,该对象的实例在onReceive被调用之后就会在任意时间内被销毁,而通过动态方式注册的广播接收器,则需要在Activity进入停止或者销毁状态的时候使用unregisterReceiver方法手动注销。

 //注销广播接收器
unregisterReceiver(receiver);

创建广播接收器也很简单,只需要去继承BroadcastRecevice并实现OnReceive方法即可,当广播发送后,系统会去检查广播接收器的过滤器与广播所发送的Intent是否一致, 如果一致调用OnReceive方法,若没有,广播接收器会一直存在着。

 public class MyReceiver extends BroadcastReceiver {

     @Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
}
}

注意事项:

BroadcastReceiver的生命周期只有10秒,不要在OnReceive方法内执行任何耗时操作,若要执行耗时操作可以通过发送Intent给Service操作,切记不能去开子线程,由于BroadcastReceiver只有10秒的生命周期,当宿主线程挂了,那么子线程也自动销毁了。

广播(Broadcast):

先来说下广播的种类,分为三种:

普通广播(Normal Broadcasts):

1、所有广播接收者都可以接收到的广播,同级别的接收者接收顺序随机不确定。

2、不能拦截广播的继续传播也不能处理处理广播

3、同级别动态注册高于静态注册

有序广播(Ordered Broadcasts):

1、按照接收者的优先级接收,优先级可以在intnt-filter里的priority里设置,值越大,优先级越高。

2、可以拦截广播的继续传播,高级别的广播接收器可以决定低级别的广播接收器是否能接收到广播。可以处理广播。

3、同级别动态注册高于静态注册

黏性广播(Sticky Broadcasts):

1、不能处理广播传递给下一个接收者,而且广播一直存在,不销毁。(不常用)

发送广播的方式:

以上3种广播的发送方式分别是:

Context.sendBroadcast()

Context.sendOrderBroadcast()

Context.sendStickyBroadcast()

随手写了个简单小demo,看下效果:

广播接收类:

 package com.example.broadcasttest;

 import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast; public class MyBroadcastReceive extends BroadcastReceiver { @Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "广播被收到了!", Toast.LENGTH_SHORT).show();
} }

主程序类:

 package com.example.broadcasttest;

 import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; public class MainActivity extends Activity { private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); this.bt=(Button) findViewById(R.id.button);
bt.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
Intent intent=new Intent();
intent.putExtra("msg", "你好,我是一个广播");
intent.setAction("com.lcw.broadcast");
intent.setClass(MainActivity.this, MyBroadcastReceive.class); MainActivity.this.sendBroadcast(intent);
}
}); } }

AndroidManifest.xml

         <receiver
android:name="com.example.broadcasttest.MyBroadcastReceive"
>
<intent-filter>
<action android:name="com.lcw.broadcast"></action>
</intent-filter>
</receiver>

配合PendingIntent和广播机制实现一个小闹钟:

先看来先什么是PendingIntent:

Intent的主要功能是表示用户的一种操作意图,当用户使用Intent之后则立刻执行用户所需要的操作,但是在Android之中也提供了一个PendingIntent操作,表示的是将要发生的操作,所谓的将要发生的Intent指的是在当前的Activity不立即使用此Intent进行处理,而将此Intent封装后传递给其他的Activity程序,而其他的Activity程序在需要使用此Intent时才进行操作。(更简单来讲:PendingIntent就是Intent的延迟包装类)

下面是PendingIntent的一些常用API:

No.
方法及常量
类型
描述
1
public static final int FLAG_CANCEL_CURRENT
常量
重新生成一个新的PendingIntent对象
2
public static final int FLAG_NO_CREATE
常量
如果不存在PendingIntent对象,则创建一个新的
3
public static final int FLAG_ONE_SHOT
常量
创建的PendingIntent对象只使用一次
4
public static final int FLAG_UPDATE_CURRENT
常量
如果PendintIntent对象已经存在,则直接使用,并且实例化一个新的Intent对象
5
public static PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags)
普通
通过PendingIntent启动一个新的Activity
6
public static PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags)
普通
通过PendingIntent启动一个新的Broadcast
7
public static PendingIntent getService(Context context, int requestCode, Intent intent, int flags)
普通
通过PendingIntent启动一个新的Service

好了,直接代码说话吧,国际惯例先看下效果图:

  

上图的效果是利用PendingIntent包装一个意图为系统闹钟的Intent延迟到指定时间发送广播,然后定义了一个广播接收器不断扫描系统,一旦接收到此广播立即在广播接受器的OnReceive方法里调用另一个Activity,而这个Activity仅仅是一个对话框用来显示信息,如二图。由于使用到了广播机制,所以就算不开着这个Activity也可以在后台监控着这个广播。

看下具体代码吧,首先是这个对话框类,很简单的一个AlertDialog

 package com.example.alarmtest;

 import java.text.SimpleDateFormat;
import java.util.Date; import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle; /**
*
* 闹钟警报类(对话框显示)
*
*/
public class AlarmActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new AlertDialog.Builder(AlarmActivity.this)
.setIcon(R.drawable.ic_launcher)
.setTitle("闹钟提醒")
.setMessage(
"闹钟响起,当前时间为:"
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date()))
.setPositiveButton("关闭", new DialogInterface.OnClickListener() { @Override
public void onClick(DialogInterface dialog, int which) {
AlarmActivity.this.finish();
}
}).show();
}
}

再来看下广播接收器类,这里只是在Receive方法里调用上面那个Activity

 package com.example.alarmtest;

 import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
*
* 广播接收类(跳转闹钟提醒类)
*
*/
public class AlarmBroadcastReceiver extends BroadcastReceiver { @Override
public void onReceive(Context context, Intent intent) {
Intent intent2=new Intent(context,AlarmActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
} }

看下主程序类

 package com.example.alarmtest;

 import java.util.Calendar;

 import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.TimePicker.OnTimeChangedListener; public class MainActivity extends Activity {
// 声明界面控件
private TimePicker timePicker;
private TextView textView;
private Button set;
private Button cancel; // 变量
private int hourOfDay = 0;
private int minute = 0; // 日期操作
private Calendar calendar; // 闹钟管理
private AlarmManager alarmManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();// 初始化控件
initAction();// 初始化事件
} private void initAction() {
this.timePicker.setOnTimeChangedListener(new OnTimeChangedListener() {// 设置时间控件监听 @Override
public void onTimeChanged(TimePicker view, int hourOfDay,
int minute) {// 这是回调函数,hourOfDay指当前选中时间,minute指当前选中分钟
// 实例化并设置Calendar类
MainActivity.this.calendar = Calendar.getInstance();
MainActivity.this.calendar.setTimeInMillis(System
.currentTimeMillis());
MainActivity.this.calendar.set(Calendar.HOUR_OF_DAY,
hourOfDay);
MainActivity.this.calendar.set(Calendar.MINUTE, minute);
MainActivity.this.calendar.set(Calendar.SECOND, 0);
// 存储变量值,便于一会更新TextView控件
MainActivity.this.hourOfDay = hourOfDay;
MainActivity.this.minute = minute; }
}); this.set.setOnClickListener(new OnClickListener() {// 设置确定按钮监听 @Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,
AlarmBroadcastReceiver.class);
intent.setAction("com.lcw.alarm");
PendingIntent operation = PendingIntent.getBroadcast(
MainActivity.this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);// 启动一个广播,PendingIntent为Intent的包装
MainActivity.this.alarmManager
.set(AlarmManager.RTC_WAKEUP,
MainActivity.this.calendar.getTimeInMillis(),
operation);
MainActivity.this.textView.setText("闹钟时间:"
+ MainActivity.this.hourOfDay + "时"
+ MainActivity.this.minute + "分" + "00秒");
Toast.makeText(MainActivity.this, "闹钟设置完毕!", Toast.LENGTH_SHORT)
.show(); }
}); this.cancel.setOnClickListener(new OnClickListener() {// 取消按钮监听 @Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,
AlarmBroadcastReceiver.class);
intent.setAction("com.lcw.alarm");
PendingIntent operation = PendingIntent.getBroadcast(
MainActivity.this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
MainActivity.this.alarmManager.cancel(operation);
MainActivity.this.textView.setText("当前闹钟未设置");
Toast.makeText(MainActivity.this, "闹钟已删除!",
Toast.LENGTH_SHORT).show();
}
}); } private void initView() {
this.timePicker = (TimePicker) findViewById(R.id.timepicker);
this.timePicker.setIs24HourView(true);// 设置时间控件24小时制
this.textView = (TextView) findViewById(R.id.timetext);
this.set = (Button) findViewById(R.id.set);
this.cancel = (Button) findViewById(R.id.cancel); MainActivity.this.alarmManager = (AlarmManager) MainActivity.this
.getSystemService(ALARM_SERVICE);// 获取系统闹钟管理实例
} }

安卓开发笔记——Broadcast广播机制(实现自定义小闹钟)的更多相关文章

  1. 安卓开发笔记——自定义广告轮播Banner(实现无限循环)

    关于广告轮播,大家肯定不会陌生,它在现手机市场各大APP出现的频率极高,它的优点在于"不占屏",可以仅用小小的固定空位来展示几个甚至几十个广告条,而且动态效果很好,具有很好的用户& ...

  2. [开发技巧]·Numpy广播机制的深入理解与应用

    [开发技巧]·Numpy广播机制的深入理解与应用 1.问题描述 我们在使用Numpy进行数据的处理时,经常会用到广播机制来简化操作,例如在所有元素都加上一个数,或者在某些纬度上作相同的操作.广播机制很 ...

  3. 安卓开发笔记——丰富多彩的TextView

    随手笔记,记录一些东西~ 记得之前写过一篇文章<安卓开发笔记——个性化TextView(新浪微博)>:http://www.cnblogs.com/lichenwei/p/4411607. ...

  4. 安卓开发笔记——关于开源项目SlidingMenu的使用介绍(仿QQ5.0侧滑菜单)

    记得去年年末的时候写过这个侧滑效果,当时是利用自定义HorizontalScrollView来实现的,效果如下: 有兴趣的朋友可以看看这篇文件<安卓开发笔记——自定义HorizontalScro ...

  5. 安卓开发笔记——打造万能适配器(Adapter)

    为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...

  6. 安卓开发笔记——关于Handler的一些总结(上)

    接上篇文章<安卓开发笔记——关于AsyncTask的使用>,今天来讲下在安卓开发里"重中之重"的另一个异步操作类Handler. 今天打算先讲下关于Handler的一些 ...

  7. 安卓开发笔记——深入Activity

    在上一篇文章<安卓开发笔记——重识Activity >中,我们了解了Activity生命周期的执行顺序和一些基本的数据保存操作,但如果只知道这些是对于我们的开发需求来说是远远不够的,今天我 ...

  8. 安卓开发笔记——TabHost组件(二)(实现底部菜单导航)

    上面文章<安卓开发复习笔记——TabHost组件(一)(实现底部菜单导航)>中提到了利用自定义View(ImageView+TextView)来设置一个底部菜单的样式 这边再补充一种更为灵 ...

  9. 安卓开发笔记——TabHost组件(一)(实现底部菜单导航)

    什么是TabHost? TabHost组件的主要功能是可以进行应用程序分类管理,例如:在用户使用windows操作系统的时候,经常见到如图所示的图形界面.     TabHost选项卡,说到这个组件, ...

随机推荐

  1. 连接池(Connection Pool)技术

    解释: 连接池(Connection Pool)技术的核心思想是:连接复用,通过建立一个数据库连接池以及一套连接使用.分配.管理策略,使得该连接池中的连接可以得到高效.安全的复用,避免了数据库连接频繁 ...

  2. 火狐FireFox57不支持Tab Mix Plus插件的问题

    火狐的Tab Mix Plus插件管理标签页很好用,但是在这次升级到57版本后不能用了,也没找到合适的替代品. 该插件一个很常用的功能是在新建的标签页打开网页(而不是在当前页上跳转),该功能直接修改C ...

  3. 【MySql 】is not allowed to connect to this MySql server 无法访问远程MySQL数据库

    问题:访问远程MySQL数据库时报错[is not allowed to connect to this MySql server ]不允许访问,因为MySQL默认只有本机localhost能够访问M ...

  4. mongo源码学习(四)服务入口点ServiceEntryPoint

    在上一篇博客mongo源码学习(三)请求接收传输层中,稍微分析了一下TransportLayer的作用,这篇来看下ServiceEntryPoint是怎么做的. 首先ServiceEntryPoint ...

  5. ubuntu apt-get 安装指定版本软件

    有时候 Ubuntu安装软件时候会提示你缺少对应版本的软件,这时候你就需要用到 sudo apt-get install softname=version 来安装对应的软件. sudo apt-get ...

  6. python 字符串和整数,浮点型互相转换

    在编程当中,经常要用到字符串的互相转换, 现在记录 python 里面的字符串和整数是怎么转换的. int(str) 函数将 符合整数的规范的字符串 转换成 int 型. num2 = "1 ...

  7. MySql5.7配置文件my.cnf设置

    # MySql5.7配置文件my.cnf设置[client]port = 3306socket = /tmp/mysql.sock [mysqld]########################## ...

  8. 基于html5 canvas 的客户端异步上传图片的插件,支持客户端压缩图片尺寸

    /** * Created by xx on 15-05-28. * 基于html5 canvas 的客户端异步上传画片的插件 * 在实际应用中,常常要用于上传图片的功能.在现在越来越多的手机weba ...

  9. Qt判断操作系统代码

    Qt4的时候是如下宏定义.Qt5,有所不同.   #include <QtGlobal> ... #ifdef Q_OS_MAC // mac #endif #ifdef Q_OS_LIN ...

  10. 【2】JVM-JAVA对象的访问

    Java中对象的访问 JAVA是面向对象的语言,那么在JAVA虚拟机中,存在非常多的对象,对象访问是无处不在的.即时是最简单的访问,也会涉及到JAVA栈.JAVA堆.方法区这三个非常重要的内存区域之间 ...