美文网首页程序员Android优秀开源优秀案例
Android:Moring-早安闹钟开发过程记录(一)

Android:Moring-早安闹钟开发过程记录(一)

作者: 黑丫山上小旋风 | 来源:发表于2016-01-18 22:16 被阅读2706次

    该文章用于记录整理开发早安闹钟过程的思路及知识点

    APP下载地址:http://pre.im/app/ecbcecb034322b2ada7376c07cf3376c
    二维码:

    Moring二维码.png

    1.程序介绍

    想做这样一个APP源于我经常在睡梦中轻易的把闹钟关掉,导致起不来,各种迟到,并且醒了以后完全不知道闹钟竟然响过,而且经常早上时间来不及了,穿好衣服出了门才发现不是太冷就是太热。

    2. 界面布局

    为了让HomeActivity的逻辑不会过于复杂,添加了三个Fragment,独立完成各自的逻辑。

    • FragmentAlarm
      用于显示闹钟的相关信息,并处理相关逻辑。核心控件为一个ListView,
      在Item中使用RelativeLayout实现点击出现编辑菜单。


      FragmentAlarm.jpg

      附上菜单动画的代码

    RelativeLayout rl_main = (RelativeLayout) view.findViewById(R.id.rl_main_item);LinearLayout ll_button = (LinearLayout) view.findViewById(R.id.ll_button_item);
    final Button bt_delete = (Button) view.findViewById(R.id.bt_delete_item);final Button bt_update = (Button) view.findViewById(R.id.bt_update_item);
    final SwitchButton sb= (SwitchButton) view.findViewById(R.id.bt_turn_item);
    float back = ll_button.getWidth();
    float front = rl_main.getWidth();float width = back / front;
    ll_button.setMinimumHeight(rl_main.getHeight());
    Log.d("alarm", width + "宽度");TranslateAnimation ta;
    if(isMenuOn){    
          //开着的就关    
            ta= new TranslateAnimation(Animation.RELATIVE_TO_SELF, width, Animation.RELATIVE_TO_SELF, 0f,Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);    
            onMenu=null;    
            isMenuOn=false;
    }else{    
            ta= new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, width, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f); 
            onMenu=view;    
            isMenuOn=true;
    }
    ta.setDuration(200);
    ta.setFillAfter(true);
    

    View onMenu用来接收当前有菜单开启的item,便于点击下一个Item的时候关闭该菜单,Boolean isMenuOn用于判断当前是否有菜单开启

    • FragmentWeather
      用于显示天气的相关信息,并处理相关逻辑。
      布局较为简单不进行赘述。
      *FragmentMenu
      用于显示侧滑菜单,侧滑菜单核心控件为ListView

    3.功能分析

    • 闹钟功能模块
      -添加闹钟
      核心逻辑:将用户添加的闹钟的各种信息记录到数据库中,同时在点
      击完成的时候将数据传给FragmentAlarm,刷新UI。
      用到的类AlarmInfo.class(闹钟信息对象),AlarmInfoDao(数据库读取工具类)。
      -修改闹钟
      与添加闹钟相同,返回数据时通过不同的RequestCode来与添加闹钟区分
      -启动闹钟定时任务
      AlarmManager
      通过getSystemService(ALARM_SERVICE)获取到AlarmManager对象
      AlarmManger中有set()和setRepeating()方法用于一次性定时任务和重复定时任务
      但在实际测试中发现会有不同程度的delay,(PS.小米真的很严重)
      通过查阅官方文档可知
      
    在API 19以后这两个方法将不再精准,如果需要使用精确定时任务,应该使用setExact();(API 19以前没有问题)
    -因此在设置定时任务时加一个判断(由于该方法在多处进行调用,我把它单独封装成了一个类)
    
    public void startAlarm(AlarmManager mAlamManager, PendingIntent pi){   
            //设置定时任务触发的时间 
            Calendar c=Calendar.getInstance();                     
            c.set(Calendar.HOUR_OF_DAY,alarmInfo.getHour());    
            c.set(Calendar.MINUTE,alarmInfo.getMinute());    
            c.set(Calendar.SECOND,0);    
            c.set(Calendar.MILLISECOND, 0);    
        //  Log.d("alarm", "当前系统版本" + Build.VERSION.SDK_INT);    
            if(c.getTimeInMillis()<System.currentTimeMillis()){        
                if(Build.VERSION.SDK_INT>=19) {            
                    mAlamManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis() + 24 * 60 * 60 * 1000, pi);        
                }else{            
                    mAlamManager.set(AlarmManager.RTC_WAKEUP,     c.getTimeInMillis() + 24 * 60 * 60 * 1000, pi);
                }    
            }else{
                 if(Build.VERSION.SDK_INT>=19) {                        
                     mAlamManager.setExact(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
            }else{
                     mAlamManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
            } 
         }
    }
    

    -问题来了:setExact();只能执行一次性定时任务如何实现重复闹钟?
    这里我最后采取得方法是在AlarmReceiver中再定一次相同的定时任务,这样在每次收到定时广播后,又重新设定一个相同的定时任务,就能达到重复精确定时的效果。
    另外,在判断闹钟应该在那几天重复,我写的逻辑是,除了一次性闹钟外,所有的重复闹钟都会在每天执行定时广播
    在AlarmReceiver中去判断今天的dayOfWeek和闹钟信息的dayOfWeek是否吻合
    吻合就启动闹钟service,否则重新定时
    用于判断当前dayOfweek的代码

    Calendar calendar=Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    int currentDay=calendar.get(Calendar.DAY_OF_WEEK)-1;
    for(int i=0;i<dayOfWeek.length;i++){
        if(currentDay==dayOfWeek[i]){
            wakePhoneAndUnlock();//点亮屏幕并解锁
            ringAlarm();
        }
    

    这里用到了点亮屏幕和解锁,也贴一下代码,这段代码是我在CSDN上学到的不知道哪位大大的代码(那天脑袋晕晕的真的忘了T_T,如果原作者看到并且希望我删除或者怎么样的请联系我,我会照做的)

        //点亮屏幕并解锁    private void wakePhoneAndUnlock() {
            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock mWakelock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.FULL_WAKE_LOCK, "WakeLock");
            mWakelock.acquire();//唤醒屏幕//......
            KeyguardManager mManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
            KeyguardManager.KeyguardLock mKeyguardLock = mManager.newKeyguardLock("Lock");
            mKeyguardLock.disableKeyguard();
            mWakelock.release();
    //释放
        }
    

    到这里闹钟的基本定时功能就完成了,另外在AlarmReceiver中加入了开机广播的监听,来开启应该要开启的闹钟

    //开机时检查是否有闹钟需要开启
    private void checkAndStartAlarm() {
        Log.d("alarm","开始检查是否有闹钟");
        AlarmInfoDao dao=new AlarmInfoDao(context);
        ArrayList<AlarmInfo> list= (ArrayList<AlarmInfo>) dao.getAllInfo();
        AlarmClock clock=new AlarmClock(context);
        for (AlarmInfo alarmInfo:list) {
            if(PrefUtils.getBoolean(context,alarmInfo.getId(),true)){
                Log.d("alarm","有闹钟,开启");
                clock.turnAlarm(alarmInfo,true);
            }
        }
    }
    //请自动忽略掉Log信息
    

    结尾

    到这里闹钟的定时任务就全部完成,在下一篇文章中分析对话框和天气早知道功能的实现
    本着开源精神附上github地址:https://github.com/JoeSteven/Moring-Alarm

    未完待续...

    相关文章

      网友评论

        本文标题:Android:Moring-早安闹钟开发过程记录(一)

        本文链接:https://www.haomeiwen.com/subject/nspkkttx.html