我的闹钟响铃的逻辑是这样设计的:
1.设置好闹钟后,立即发送一个带有唯一id的延迟意图PendingIntent广播;
2.当时间到的时候,广播接受者接收到发送过来的数据,并开启一个服务,将数据传递进去;
3.服务创建成功后,根据传递过来的数据进行响铃和振动操作,同时启动一个响铃的activity界面,将时间,标签等信息传递过去显示;
4.响铃的activity创建成功后,立即与服务进行绑定,界面上有两个按钮,暂停再响 和 关闭闹钟,分别对应服务里面的相应的方法。
5.当点击 暂停5分钟再响,会在服务里发送一个5分钟的延迟广播,同时 解绑服务-->停止服务;
当点击关闭闹钟的时候,如果该闹钟的重复周期为只响一次,则取消该闹钟的广播,更新数据库,同时 解绑服务-->停止服务;如果该闹钟的重读周期为其它,则计算与下一次闹铃最短的时间间隔,发送一个延迟广播,同时 解绑服务-->停止服务。
整体的思路概括一下:有几个闹钟,系统里就有几个广播;当一个闹钟的广播处理完成之后,根据重复周期判断是否发送下一次广播。
广播接受者的代码如下:
public class AlarmClockReceiver extends BroadcastReceiver {
private static final String TAG = "AlarmClockReceiver";
public static final String Alarm_CLOCK_RING_ONLY_ONCE = "只响一次";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("cn.edu.usts.cardhelper.alarmclock")){
Log.i(TAG, "--------------------闹钟的广播接受者-----------------------");
Bundle bundle = intent.getExtras();
int alarmClockId = bundle.getInt("alarmClockId");
int hour = bundle.getInt("hour");
int minute = bundle.getInt("minute");
String repeatCycle = bundle.getString("repeatCycle");
String ringInfo = bundle.getString("ringInfo");
int isShake = bundle.getInt("isShake");
String tag = bundle.getString("tag");
Log.i(TAG, "---接收到的闹钟id为:"+alarmClockId+"---重复周期为:"+repeatCycle+"---铃声信息:"+ringInfo+"---振动:"+isShake+"---hour:"+hour+"---minute:"+minute+"---tag:"+tag);
//开启一个服务
Intent ringIntent = new Intent(context, AlarmClockService.class);
ringIntent.putExtras(bundle);
ringIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(ringIntent);
}
}
}
服务的代码如下:
public class AlarmClockService extends Service {
public static final String TAG = "AlarmClockService";
public static final String Alarm_CLOCK_RING_ONLY_ONCE = "只响一次";
private AlarmManager alarmManager;
private MediaPlayer mediaPlayer;
private Vibrator vibrator;
private Bundle bundle;
private Intent toReceiverIntent;
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "--------------onBind----------");
return new AlarmClockRingServiceProvider();
}
@Override
public void onCreate() {
Log.i(TAG, "--------------onCreate----------");
super.onCreate();
alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
vibrator=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "--------------onStartCommand----------");
bundle = intent.getExtras();
//在闹铃界面点击 暂停再响 或 关闭 时 发送的意图
toReceiverIntent = new Intent(this , AlarmClockReceiver.class);
toReceiverIntent.setAction("cn.edu.usts.cardhelper.alarmclock");
toReceiverIntent.putExtras(bundle);
//发送到 闹铃界面的意图
Intent alarmClockRingintent = new Intent(this, AlarmClockRingActivity.class);
alarmClockRingintent.putExtras(bundle);
alarmClockRingintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(alarmClockRingintent);
String ringInfo = bundle.getString("ringInfo");
Uri audioUri = Uri.parse(ringInfo.split("##")[1]);
if( ! audioUri.equals("无")){
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setLooping(true);
mediaPlayer.setDataSource(this, audioUri);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();
}
});
}catch (Exception e) {
e.printStackTrace();
}
}
int isShake = bundle.getInt("isShake");
if(isShake == 1){
vibrator.vibrate(new long[] { 0, 1000, 1000, 1000, 1000 }, 0);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "--------------onUnbind----------");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.i(TAG, "--------------onDestroy----------");
super.onDestroy();
}
public void stopMusic(){
if(mediaPlayer != null && mediaPlayer.isPlaying()){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
public void stopVibrator(){
if(vibrator != null ){
vibrator.cancel();
vibrator = null;
}
}
//服务要暴露方法 必须要有一个中间人
private class AlarmClockRingServiceProvider extends Binder implements IAlarmClockRingServiceProvider{
@Override
public void pause5MinRing() {
stopMusic();
stopVibrator();
int alarmClockId = bundle.getInt("alarmClockId");
PendingIntent pi = PendingIntent.getBroadcast(AlarmClockService.this, alarmClockId, toReceiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+5*60*1000, pi);
Log.i(TAG, "----------5分钟后响铃的广播发送完毕!-----------");
}
@Override
public void close() {
stopMusic();
stopVibrator();
String repeatCycle = bundle.getString("repeatCycle");
int alarmClockId = bundle.getInt("alarmClockId");
int hour = bundle.getInt("hour");
int minute = bundle.getInt("minute");
if(repeatCycle.equals(Alarm_CLOCK_RING_ONLY_ONCE)){ //只响一次的闹钟 --> 取消该广播,更新数据库
alarmManager.cancel(PendingIntent.getBroadcast(AlarmClockService.this, alarmClockId, toReceiverIntent, PendingIntent.FLAG_UPDATE_CURRENT));
AlarmClockDao dao = new AlarmClockDao(AlarmClockService.this);
dao.updataState(alarmClockId, 0);
Log.i(TAG, "--只响一次的闹钟广播已取消,数据库更新完毕!!-----");
}else{ // --> 发送下一次闹钟的广播
int dTime = NextRingTimeProvider.showRingTimeByRepeatCycle(repeatCycle, hour, minute);
PendingIntent pi = PendingIntent.getBroadcast(AlarmClockService.this, alarmClockId, toReceiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+dTime, pi);
Log.i(TAG, "--距离下一次闹钟的剩余时间为"+RingTextUtil.showDTimeText(dTime)+"-----");
}
}
@Override
public void oneMinClose() {
pause5MinRing();
}
}
}
public class AlarmClockRingActivity extends Activity implements OnClickListener {
public static final String TAG = "AlarmClockRingActivity";
private TextView tv_time;
private TextView tv_tag;
private Button btn_pause_ring;
private Button btn_close;
private IAlarmClockRingServiceProvider ringServiceProvider; //服务的中间人接口对象
private MyConn conn;
private Intent serviceIntent;
private boolean flag_is_pause_or_close;
@SuppressLint("HandlerLeak")
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
if( ! flag_is_pause_or_close){
ringServiceProvider.oneMinClose();
AlarmClockRingActivity.this.finish();
Log.i(TAG, "--------响铃一分钟无反应。。--成功调用服务里五分钟后再响的方法!----------------");
}else{
Log.i(TAG, "--------点击了暂停或关闭闹钟。--一分钟失效!---------------");
}
}
}, 60*1000);
};
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.alarm_clcok_ring_activity);
//锁屏状态下 唤醒屏幕 保持常亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
tv_time = (TextView) this.findViewById(R.id.tv_alarm_clock_ring_time);
tv_tag = (TextView) this.findViewById(R.id.tv_alarm_clock_ring_tag);
btn_pause_ring = (Button) this.findViewById(R.id.btn_alarm_clock_ring_pause_ring);
btn_close = (Button) this.findViewById(R.id.btn_alarm_clock_ring_close);
btn_pause_ring.setOnClickListener(this);
btn_close.setOnClickListener(this);
handler.sendEmptyMessage(0);
}
@Override
protected void onStart() {
super.onStart();
//绑定闹钟到来的服务
conn = new MyConn();
serviceIntent = new Intent(this, AlarmClockService.class);
bindService(serviceIntent, conn, 0);
Bundle bundle = getIntent().getExtras();
// String hour = bundle.getInt("hour")+"";
// String minute = bundle.getInt("minute")+"";
Calendar calendar = Calendar.getInstance();
String hour = calendar.get(Calendar.HOUR_OF_DAY)+"";
String minute = calendar.get(Calendar.MINUTE)+"";
if(hour.length() == 1){
hour = "0"+hour;
}
if(minute.length() == 1){
minute = "0"+minute;
}
tv_time.setText(hour+":"+minute);
tv_tag.setText(bundle.getString("tag"));
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_alarm_clock_ring_pause_ring:
flag_is_pause_or_close =true;
ringServiceProvider.pause5MinRing();
finish();
break;
case R.id.btn_alarm_clock_ring_close:
flag_is_pause_or_close =true;
ringServiceProvider.close();
finish();
break;
}
}
private class MyConn implements ServiceConnection{
//当服务失去连接的时候调用(一般进程挂了,服务被异常杀死)
@Override
public void onServiceDisconnected(ComponentName name) {
}
//当服务被连接的时候调用 服务识别成功 绑定的时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
ringServiceProvider = (IAlarmClockRingServiceProvider) service;
Log.i(TAG, "-------在activity里面得到了服务的中间人对象-------------");
}
}
@Override
protected void onStop() {
super.onPause();
}
@Override
protected void onDestroy() {
unbindService(conn);
stopService(serviceIntent);
super.onDestroy();
}
@Override
public void onBackPressed() {
return;
}
}
由于android手机重启之后,会清空所有的广播,所以要注册一个手机重启的接受者,当手机重启成功后,读取闹钟的数据库,发送响应的延迟广播。
代码如下:
public class BootCompleteReceiver extends BroadcastReceiver {
private static final String TAG = "BootCompleteReceiver";
public static final String Alarm_CLOCK_RING_ONLY_ONCE = "只响一次";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "----------手机重启完毕!-------------");
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//TODO 读取数据库 发送下一次闹钟的广播
AlarmClockDao dao = new AlarmClockDao(context);
List clockInfos = dao.findAll();
for (AlarmClockInfo clockInfo : clockInfos) {
if(clockInfo.getState() != 0){
Intent alarmIntent = new Intent(context, AlarmClockReceiver.class);
alarmIntent.setAction("cn.edu.usts.cardhelper.alarmclock");
Bundle bundle = new Bundle();
bundle.putInt("alarmClockId", clockInfo.getId());
bundle.putString("repeatCycle",clockInfo.getRepeatCycle());
bundle.putInt("hour", clockInfo.getHour());
bundle.putInt("minute", clockInfo.getMinute());
bundle.putString("ringInfo", clockInfo.getRingInfo());
bundle.putInt("isShake", clockInfo.getShake());
bundle.putString("tag", clockInfo.getTag());
alarmIntent.putExtras(bundle);
PendingIntent pi = PendingIntent.getBroadcast(context, clockInfo.getId(), alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int dTime = NextRingTimeProvider.showRingTimeByRepeatCycle(clockInfo.getRepeatCycle(), clockInfo.getHour(), clockInfo.getMinute());
if(clockInfo.getRepeatCycle().equals(Alarm_CLOCK_RING_ONLY_ONCE)){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, clockInfo.getHour());
calendar.set(Calendar.MINUTE, clockInfo.getMinute());
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
if(System.currentTimeMillis() < calendar.getTimeInMillis()){
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+dTime, pi);
Log.i(TAG, "--重启广播发送成功! 只响一次的闹钟时间未到,广播已发送--闹钟ID:"+clockInfo.getId()+"--repeatCycle"+clockInfo.getRepeatCycle()+"--hour:"+clockInfo.getHour()+"---minute:"+clockInfo.getMinute()+"---铃声为:"+clockInfo.getRingInfo()+"---振动:"+clockInfo.getShake()+"---tag:"+clockInfo.getTag());
}
}else{
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+dTime, pi);
Log.i(TAG, "--重启广播发送成功! --闹钟ID:"+clockInfo.getId()+"--repeatCycle"+clockInfo.getRepeatCycle()+"--hour:"+clockInfo.getHour()+"---minute:"+clockInfo.getMinute()+"---铃声为:"+clockInfo.getRingInfo()+"---振动:"+clockInfo.getShake()+"---tag:"+clockInfo.getTag());
}
}
}
}
}