Android 闹钟 开发过程记录(五)
2015-03-01 13:25
513 查看
我的闹钟响铃的逻辑是这样设计的:
1.设置好闹钟后,立即发送一个带有唯一id的延迟意图PendingIntent广播;
2.当时间到的时候,广播接受者接收到发送过来的数据,并开启一个服务,将数据传递进去;
3.服务创建成功后,根据传递过来的数据进行响铃和振动操作,同时启动一个响铃的activity界面,将时间,标签等信息传递过去显示;
4.响铃的activity创建成功后,立即与服务进行绑定,界面上有两个按钮,暂停再响 和 关闭闹钟,分别对应服务里面的相应的方法。
5.当点击 暂停5分钟再响,会在服务里发送一个5分钟的延迟广播,同时 解绑服务-->停止服务;
当点击关闭闹钟的时候,如果该闹钟的重复周期为只响一次,则取消该闹钟的广播,更新数据库,同时 解绑服务-->停止服务;如果该闹钟的重读周期为其它,则计算与下一次闹铃最短的时间间隔,发送一个延迟广播,同时 解绑服务-->停止服务。
整体的思路概括一下:有几个闹钟,系统里就有几个广播;当一个闹钟的广播处理完成之后,根据重复周期判断是否发送下一次广播。
广播接受者的代码如下:
服务的代码如下:
响铃界面的代码如下:
由于android手机重启之后,会清空所有的广播,所以要注册一个手机重启的接受者,当手机重启成功后,读取闹钟的数据库,发送响应的延迟广播。
代码如下:
闹钟的广播接收者 和 重启的广播接受者 都需要在清单文件中配置一下:
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<AlarmClockInfo> 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()); } } } } }
闹钟的广播接收者 和 重启的广播接受者 都需要在清单文件中配置一下:
<!-- android:process=":remote" 会另外开一个进程运行 android:exported="false" 表示不接受来自外部的广播。 --> <receiver android:name=".receiver.AlarmClockReceiver" android:exported="false" android:process=":remote" > <intent-filter android:priority="1000" > <action android:name="cn.edu.usts.cardhelper.alarmclock" /> </intent-filter> </receiver>
<receiver android:name=".receiver.BootCompleteReceiver" > <intent-filter android:priority="1000" > <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
相关文章推荐
- Android 闹钟 开发过程记录(二)
- Android 闹钟 开发过程记录(三)
- Android:Moring-早安闹钟开发过程记录(二)
- Android:Moring-早安闹钟开发过程记录(三)
- Android 闹钟 开发过程记录(七)
- Android 闹钟 开发过程记录(四)
- Android:Moring-早安闹钟开发过程记录(四)
- Android:Moring-早安闹钟开发过程记录(一)
- Android 闹钟 开发过程记录(六)
- Android 闹钟 开发过程记录(一)
- android 实用闹钟开发过程记(一)--创建数据库
- 基于Eclipse的Android JNI层测试应用开发过程记录
- 初学android开发的一些过程记录
- android 实用闹钟开发过程记(二)--sqlite数据库的操作
- Android 手机影音 开发过程记录(二)
- Android 手机影音 开发过程记录(三)
- android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录
- android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录
- android 最新 NDK r8 在window下开发环境搭建 安装配置与使用 详细图文讲解,完整实际配置过程记录
- cocos2d-x-2.1使用Xcode整合ios与android开发代码 - 过程记录