Android系统原生应用解析之桌面闹钟及相关原理应用之时钟任务的应用(一)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 前段时间我一个朋友在面试回来问我:那个公司要5天之内完成一个项目,功能包括每天早上6点开始执行定时任务,大批量图片上传,大批量数据库同步。我心想,后两个功能还好说,可就是每天早上6点开始执行的这种定时任务如何搞定? 有了问题,自然要琢磨怎么解决,如果接触的知识面不够,或者没有系统的学习...

前段时间我一个朋友在面试回来问我:那个公司要5天之内完成一个项目,功能包括每天早上6点开始执行定时任务,大批量图片上传,大批量数据库同步。我心想,后两个功能还好说,可就是每天早上6点开始执行的这种定时任务如何搞定?


有了问题,自然要琢磨怎么解决,如果接触的知识面不够,或者没有系统的学习Android API,例如不知道AlarmManager,自然是不知道如何启动定时任务的,当时我也不知道这个的存在,突然心头一闪,那手机上的闹钟可不就是定时任务吗?


多亏了这心头一闪,知道从系统闹钟看看一个闹钟这种标准的定时任务是如何完成的,正好手中刚刚下载完完整的安卓源码,也编译通过了,在源码的目录/packages/中找到了DeskClock文件夹,一看便知是闹钟了。


为了不破坏原生系统的完整性,我将这个工程拷了出来,导入了Studio进行分析,看看如何启动一个定时任务(我自己心里是觉得应该不会有一个服务在后台一直跑着用来监控时间),导入Studio之后进行简单的环境配置编译,跑了起来:

不得不说原生应用还是很漂亮的,为了达到我们的研究目的,我们只选择一个闹钟是如何被创建以及是如何被响应的。


首先我们需要找到一个闹钟任务是如何被创建及打开的,我没有直接去找闹钟是如何创建的,我去找了闹钟是如何被打开的,因为在item上有个开关,我找到了那个开关:

这个开关位于com.android.deskclock.AlarmClockFragment内,AlarmClockFragment内含有一个Adapter内部类,在Adapter的getView方法中找到了这个小开关的触发事件:

		@Override
		public 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;
		}

		...

		@Override
		public 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() {
				@Override
				public 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 AsyncTask<Void, Void, AlarmInstance> updateTask = new AsyncTask<Void, Void, AlarmInstance>() {
				@Override
				protected AlarmInstance doInBackground(Void... parameters) {
					ContentResolver cr = context.getContentResolver();

					// Dismiss all old instances
					AlarmStateManager.deleteAllInstances(context, alarm.id);

					// Update alarm
					Alarm.updateAlarm(cr, alarm);
					if (alarm.enabled) {
						return setupAlarmInstance(context, alarm);
					}

					return null;
				}

				@Override
				protected void onPostExecute(AlarmInstance instance) {
					if (popToast && instance != null) {
						AlarmUtils.popAlarmSetToast(context, instance.getAlarmTime().getTimeInMillis());
					}
				}
			};
			updateTask.execute();
		}
它内部执行了一个异步任务,任务的核心调用的是setupAlarmInstance:

		private 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 manager
			AlarmStateManager.registerInstance(context, newInstance, true);
			return newInstance;
		}
这里的意思是,将闹钟数据添加到ContentProvider中,以便将数据共享给其它应用。接下来调用了AlarmStateManager.registerInstance:

		public static void registerInstance(Context context, AlarmInstance instance,
			boolean updateNextAlarm) {

			...

			// The caller prefers to handle updateNextAlarm for optimization
			if (updateNextAlarm) {
			    updateNextAlarm(context);
			}
		}
这段代码中本来有很长的一段代码,用来判断闹钟的各个时间段的执行情况,为了避免干扰我们的主流程,对代码进行了删减处理,我们从上一段代码可知,这里的updateNextAlarm值为true,进入到updateNextAlarm:

    public 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的各种时钟任务应用。








目录
相关文章
|
23天前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
19天前
|
安全 前端开发 Android开发
探索移动应用与系统:从开发到操作系统的深度解析
在数字化时代的浪潮中,移动应用和操作系统成为了我们日常生活的重要组成部分。本文将深入探讨移动应用的开发流程、关键技术和最佳实践,同时分析移动操作系统的核心功能、架构和安全性。通过实际案例和代码示例,我们将揭示如何构建高效、安全且用户友好的移动应用,并理解不同操作系统之间的差异及其对应用开发的影响。无论你是开发者还是对移动技术感兴趣的读者,这篇文章都将为你提供宝贵的见解和知识。
|
20天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
21天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
23天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
24天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
55 3
|
2天前
|
安全 搜索推荐 数据挖掘
陪玩系统源码开发流程解析,成品陪玩系统源码的优点
我们自主开发的多客陪玩系统源码,整合了市面上主流陪玩APP功能,支持二次开发。该系统适用于线上游戏陪玩、语音视频聊天、心理咨询等场景,提供用户注册管理、陪玩者资料库、预约匹配、实时通讯、支付结算、安全隐私保护、客户服务及数据分析等功能,打造综合性社交平台。随着互联网技术发展,陪玩系统正成为游戏爱好者的新宠,改变游戏体验并带来新的商业模式。
|
27天前
|
机器学习/深度学习 人工智能 数据处理
【AI系统】NV Switch 深度解析
英伟达的NVSwitch技术是高性能计算领域的重大突破,旨在解决多GPU系统中数据传输的瓶颈问题。通过提供比PCIe高10倍的带宽,NVLink实现了GPU间的直接数据交换,减少了延迟,提高了吞吐量。NVSwitch则进一步推动了这一技术的发展,支持更多NVLink接口,实现无阻塞的全互联GPU系统,极大提升了数据交换效率和系统灵活性,为构建强大的计算集群奠定了基础。
58 3
|
27天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
26天前
|
前端开发 Android开发 UED
移动应用与系统:从开发到优化的全面解析####
本文深入探讨了移动应用开发的全过程,从最初的构思到最终的发布,并详细阐述了移动操作系统对应用性能和用户体验的影响。通过分析当前主流移动操作系统的特性及差异,本文旨在为开发者提供一套全面的开发与优化指南,确保应用在不同平台上均能实现最佳表现。 ####
27 0

推荐镜像

更多