未备案网站 赚钱,做服务网站发展背景,网页界面设计的要求是什么,wordpress网站logo前段时间我一个朋友在面试回来问我#xff1a;那个公司要5天之内完成一个项目#xff0c;功能包括每天早上6点开始执行定时任务#xff0c;大批量图片上传#xff0c;大批量数据库同步。我心想#xff0c;后两个功能还好说#xff0c;可就是每天早上6点开始执行的这种定时…前段时间我一个朋友在面试回来问我那个公司要5天之内完成一个项目功能包括每天早上6点开始执行定时任务大批量图片上传大批量数据库同步。我心想后两个功能还好说可就是每天早上6点开始执行的这种定时任务如何搞定 有了问题自然要琢磨怎么解决如果接触的知识面不够或者没有系统的学习Android API例如不知道AlarmManager自然是不知道如何启动定时任务的当时我也不知道这个的存在突然心头一闪那手机上的闹钟可不就是定时任务吗 多亏了这心头一闪知道从系统闹钟看看一个闹钟这种标准的定时任务是如何完成的正好手中刚刚下载完完整的安卓源码也编译通过了在源码的目录/packages/中找到了DeskClock文件夹一看便知是闹钟了。 为了不破坏原生系统的完整性我将这个工程拷了出来导入了Studio进行分析看看如何启动一个定时任务(我自己心里是觉得应该不会有一个服务在后台一直跑着用来监控时间)导入Studio之后进行简单的环境配置编译跑了起来 不得不说原生应用还是很漂亮的为了达到我们的研究目的我们只选择一个闹钟是如何被创建以及是如何被响应的。 首先我们需要找到一个闹钟任务是如何被创建及打开的我没有直接去找闹钟是如何创建的我去找了闹钟是如何被打开的因为在item上有个开关我找到了那个开关
这个开关位于com.android.deskclock.AlarmClockFragment内AlarmClockFragment内含有一个Adapter内部类在Adapter的getView方法中找到了这个小开关的触发事件 Overridepublic View getView(int position, View convertView, ViewGroup parent) {...View v;if (convertView null) {v newView(mContext, getCursor(), parent);} else {v convertView;}bindView(v, mContext, getCursor());return v;}...Overridepublic void bindView(final View view, Context context, final Cursor cursor) {final Alarm alarm new Alarm(cursor);Object tag view.getTag();...final CompoundButton.OnCheckedChangeListener onOffListener new CompoundButton.OnCheckedChangeListener() {Overridepublic void onCheckedChanged(CompoundButton compoundButton, boolean checked) {if (checked ! alarm.enabled) {setDigitalTimeAlpha(itemHolder, checked);alarm.enabled checked;asyncUpdateAlarm(alarm, alarm.enabled);}}};...itemHolder.onoff.setOnCheckedChangeListener(onOffListener);...}onOffListener引用的对象便是闹钟开关的实现逻辑了它调用了asyncUpdateAlarm方法private void asyncUpdateAlarm(final Alarm alarm, final boolean popToast) {final Context context AlarmClockFragment.this.getActivity().getApplicationContext();final AsyncTaskVoid, Void, AlarmInstance updateTask new AsyncTaskVoid, Void, AlarmInstance() {Overrideprotected AlarmInstance doInBackground(Void... parameters) {ContentResolver cr context.getContentResolver();// Dismiss all old instancesAlarmStateManager.deleteAllInstances(context, alarm.id);// Update alarmAlarm.updateAlarm(cr, alarm);if (alarm.enabled) {return setupAlarmInstance(context, alarm);}return null;}Overrideprotected void onPostExecute(AlarmInstance instance) {if (popToast instance ! null) {AlarmUtils.popAlarmSetToast(context, instance.getAlarmTime().getTimeInMillis());}}};updateTask.execute();}它内部执行了一个异步任务任务的核心调用的是setupAlarmInstanceprivate static AlarmInstance setupAlarmInstance(Context context, Alarm alarm) {ContentResolver cr context.getContentResolver();AlarmInstance newInstance alarm.createInstanceAfter(Calendar.getInstance());newInstance AlarmInstance.addInstance(cr, newInstance);// Register instance to state managerAlarmStateManager.registerInstance(context, newInstance, true);return newInstance;}这里的意思是将闹钟数据添加到ContentProvider中以便将数据共享给其它应用。接下来调用了AlarmStateManager.registerInstancepublic static void registerInstance(Context context, AlarmInstance instance,boolean updateNextAlarm) {...// The caller prefers to handle updateNextAlarm for optimizationif (updateNextAlarm) {updateNextAlarm(context);}}这段代码中本来有很长的一段代码用来判断闹钟的各个时间段的执行情况为了避免干扰我们的主流程对代码进行了删减处理我们从上一段代码可知这里的updateNextAlarm值为true进入到updateNextAlarmpublic static void updateNextAlarm(Context context) {...AlarmNotifications.registerNextAlarmWithAlarmManager(context, nextAlarm);}...public static void registerNextAlarmWithAlarmManager(Context context, AlarmInstance instance) {// Sets a surrogate alarm with alarm manager that provides the AlarmClockInfo for the// alarm that is going to fire next. The operation is constructed such that it is ignored// by AlarmStateManager.AlarmManager alarmManager (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);int flags instance null ? PendingIntent.FLAG_NO_CREATE : 0;PendingIntent operation PendingIntent.getBroadcast(context, 0 /* requestCode */,AlarmStateManager.createIndicatorIntent(context), flags);if (instance ! null) {long alarmTime instance.getAlarmTime().getTimeInMillis();// Create an intent that can be used to show or edit details of the next alarm.PendingIntent viewIntent PendingIntent.getActivity(context, instance.hashCode(),createViewAlarmIntent(context, instance), PendingIntent.FLAG_UPDATE_CURRENT);AlarmManager.AlarmClockInfo info new AlarmManager.AlarmClockInfo(alarmTime, viewIntent);alarmManager.setAlarmClock(info, operation);} else if (operation ! null) {alarmManager.cancel(operation);}}updateNextAlarm方法中通过调用AlarmNotifications类中的registerNextAlarmWithAlarmManager方法将下一次的闹铃注册到AlarmManager歪果仁的命名清晰易懂啊registerNextAlarmWithAlarmManager的方法内部则是我们真正需要看到的首先是获取到了系统中的AlarmManager对象接着创建了一个PendingIntent对象operation这个对象用来执行当闹钟时间到的时候需要调用的广播类我们看看AlarmStateManager.createIndicatorIntent(context)方法内部是如何实现的/*** Creates an intent that can be used to set an AlarmManager alarm to set the next alarm* indicators.*/public static Intent createIndicatorIntent(Context context) {return new Intent(context, AlarmStateManager.class).setAction(INDICATOR_ACTION);}public final class AlarmStateManager extends BroadcastReceiver {...}内部则是简单的new了一个Intent这个显式的意图指定的是AlarmStateManager而AlarmStateManager则继承的是BroadcastReceiver这时我们很明白当时钟任务触发的时候会调用我们这个AlarmStateManager的广播其实AlarmStateManager这个类的内部是有很多代码了这里被我删减了以便看代码清晰。回到上一段方法中继续往下走又看到在创建PendingIntent的对象viewIntent这个对象则是用来当时钟任务启动时显示的界面我们在使用闹钟的时候会弹出一个界面让我们关掉那与我们交互的Activity就是这里被设定的createViewAlarmIntent方法内部创建的是一个显式的Activity有兴趣的可以进去看看。 一切设定好之后再通过AlarmManager的方法setAlarmClock将我们的时钟任务注册到系统系统会在我们设定的时间到达之后调用相关的Intent对象。
除了可以使用setAlarmClock方法注册一个时钟任务之外我们还可以通过cancel方法将这个任务取消。
好这就是闹钟的基本实现原理。接下里详细描述一下AlarmManager的各种时钟任务应用。