`
jandroid
  • 浏览: 1949711 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Android闹钟最终版【android源码闹钟解析】

 
阅读更多

我以前写了个复杂闹钟的demo,参见Android闹钟【复杂版】【大明进化十五】 .但是里面的bug有一些,好多人留言,所以我就看看源码,找找原因?顺便把源码代码整理出来,弄成一个完整的可以运行的apk,今天上午就整理了一下,才发现,源码处理的逻辑多一些,考虑的情况多,比如开机后接收一个广播,然后从数据库中取时间和当前时间对比,设置闹钟,当时区改变了,也会发送广播,对闹钟进行设置的。

转载请标明出处:http://blog.csdn.net/wdaming1986/article/details/7461043

有人问我:“当设置一个闹钟后,然后调系统时间超过设置的闹钟的时间,这时候闹钟响了??”

通过源码,我发现这种情况是正常的。不是bug。可以理解。

以下是我发现的几点闹钟中重要的点,分享一下:

(1)在闹钟中有AudioManager管理机制,这个机制可以申请和释放OnAudioFocusChangeListener监听。

还有mTelephonyManager对象,处理在闹钟响的时候,来电铃声的切换。

(2)广播接收闹钟,通过广播启动AlarmKlaxon这个Service,隐式启动service:

public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm";

// Play the alarm alert and vibrate the device.
        Intent playAlarm = new Intent(Alarms.ALARM_ALERT_ACTION);
        playAlarm.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
        context.startService(playAlarm);

在mainfest中,AlarmKlaxon这个服务的定义如下:

<service android:name="AlarmKlaxon"
                android:description="@string/alarm_klaxon_service_desc"
                >
            <intent-filter>
                <action android:name="com.cn.daming.deskclock.ALARM_ALERT" />
            </intent-filter>
        </service>

这个service做的是允许别的Activity打断正在响铃的铃声,播放其他的铃声,例如,闹钟响的时候来电话了。

(3)在listview中包含checkbox,这时候闹钟的处理时,activity实现一个OnItemClickListener的监听,点击每一项的监听。然后在checkbox单独拿出去写一个类,继承LinearLayout,重写setPressed()这个方法,以实现“当点击checkbox的时候不触发parent的click事件”。关键代码如下:

 @Override
    public void setPressed(boolean pressed) {
        // If the parent is pressed, do not set to pressed.
        if (pressed && ((View) getParent()).isPressed()) {
            return;
        }
        super.setPressed(pressed);
    }

下面看看我的程序截图:

红色圈的图标为我的闹钟。 点击“玲闹钟”后的界面

点击新建闹钟出现的界面 设置好时间弹出的toast。

下面我把我的主要入口类的代码贴出来

DeskClockMainActivity.java

package com.cn.daming.deskclock;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class DeskClockMainActivity extends Activity implements OnItemClickListener{
	
    static final String PREFERENCES = "AlarmClock";

    /** This must be false for production.  If true, turns on logging,
        test code, etc. */
    static final boolean DEBUG = false;

    private SharedPreferences mPrefs;
    private LayoutInflater mFactory;
    private ListView mAlarmsList;
    private Cursor mCursor;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //取自定义布局的LayoutInflater
        mFactory = LayoutInflater.from(this);
        //取getSharedPreferences中key==“AlarmClock”的值
        mPrefs = getSharedPreferences(PREFERENCES, 0);
        //获取闹钟的cursor
        mCursor = Alarms.getAlarmsCursor(getContentResolver());
        
        //更新布局界面
        updateLayout();

    }
    
    //加载更新界面布局
    private void updateLayout() {
    	setContentView(R.layout.alarm_clock);
        mAlarmsList = (ListView) findViewById(R.id.alarms_list);
        AlarmTimeAdapter adapter = new AlarmTimeAdapter(this, mCursor);
        mAlarmsList.setAdapter(adapter);
        mAlarmsList.setVerticalScrollBarEnabled(true);
        mAlarmsList.setOnItemClickListener(this);
        mAlarmsList.setOnCreateContextMenuListener(this);

        View addAlarm = findViewById(R.id.add_alarm);
        addAlarm.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    addNewAlarm();
                }
            });
        // Make the entire view selected when focused.
        addAlarm.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                public void onFocusChange(View v, boolean hasFocus) {
                    v.setSelected(hasFocus);
                }
        });

        ImageButton deskClock =
                (ImageButton) findViewById(R.id.desk_clock_button);
        deskClock.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    
                }
        });
    }
    
    private void addNewAlarm() {
        startActivity(new Intent(this, SetAlarm.class));
    }
    
    /**
     * listview的适配器继承CursorAdapter
     * @author wangxianming
     * 也可以使用BaseAdapter
     */
    private class AlarmTimeAdapter extends CursorAdapter {
        public AlarmTimeAdapter(Context context, Cursor cursor) {
            super(context, cursor);
        }

        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View ret = mFactory.inflate(R.layout.alarm_time, parent, false);

            DigitalClock digitalClock =
                    (DigitalClock) ret.findViewById(R.id.digitalClock);
            digitalClock.setLive(false);
            return ret;
        }

        //把view绑定cursor的每一项
        public void bindView(View view, Context context, Cursor cursor) {
            final Alarm alarm = new Alarm(cursor);

            View indicator = view.findViewById(R.id.indicator);

            // Set the initial resource for the bar image.
            final ImageView barOnOff =
                    (ImageView) indicator.findViewById(R.id.bar_onoff);
            barOnOff.setImageResource(alarm.enabled ?
                    R.drawable.ic_indicator_on : R.drawable.ic_indicator_off);

            // Set the initial state of the clock "checkbox"
            final CheckBox clockOnOff =
                    (CheckBox) indicator.findViewById(R.id.clock_onoff);
            clockOnOff.setChecked(alarm.enabled);

            // Clicking outside the "checkbox" should also change the state.
            //对checkbox设置监听,使里外一致
            indicator.setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        clockOnOff.toggle();
                        updateIndicatorAndAlarm(clockOnOff.isChecked(),
                                barOnOff, alarm);
                    }
            });

            DigitalClock digitalClock =
                    (DigitalClock) view.findViewById(R.id.digitalClock);

            // set the alarm text
            final Calendar c = Calendar.getInstance();
            c.set(Calendar.HOUR_OF_DAY, alarm.hour);
            c.set(Calendar.MINUTE, alarm.minutes);
            digitalClock.updateTime(c);
            digitalClock.setTypeface(Typeface.DEFAULT);

            // Set the repeat text or leave it blank if it does not repeat.
            TextView daysOfWeekView =
                    (TextView) digitalClock.findViewById(R.id.daysOfWeek);
            final String daysOfWeekStr =
                    alarm.daysOfWeek.toString(DeskClockMainActivity.this, false);
            if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
                daysOfWeekView.setText(daysOfWeekStr);
                daysOfWeekView.setVisibility(View.VISIBLE);
            } else {
                daysOfWeekView.setVisibility(View.GONE);
            }

            // Display the label
            TextView labelView =
                    (TextView) view.findViewById(R.id.label);
            if (alarm.label != null && alarm.label.length() != 0) {
                labelView.setText(alarm.label);
                labelView.setVisibility(View.VISIBLE);
            } else {
                labelView.setVisibility(View.GONE);
            }
        }
    };
    
    //更新checkbox
    private void updateIndicatorAndAlarm(boolean enabled, ImageView bar,
            Alarm alarm) {
        bar.setImageResource(enabled ? R.drawable.ic_indicator_on
                : R.drawable.ic_indicator_off);
        Alarms.enableAlarm(this, alarm.id, enabled);
        if (enabled) {
            SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
                    alarm.daysOfWeek);
        }
    }
    
    /*
     * (non-Javadoc)
     * @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
     * 创建上下文菜单
     */
    @Override
    public boolean onContextItemSelected(final MenuItem item) {
        final AdapterContextMenuInfo info =
                (AdapterContextMenuInfo) item.getMenuInfo();
        final int id = (int) info.id;
        // Error check just in case.
        if (id == -1) {
            return super.onContextItemSelected(item);
        }
        switch (item.getItemId()) {
            case R.id.delete_alarm:
                // Confirm that the alarm will be deleted.
                new AlertDialog.Builder(this)
                        .setTitle(getString(R.string.delete_alarm))
                        .setMessage(getString(R.string.delete_alarm_confirm))
                        .setPositiveButton(android.R.string.ok,
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface d,
                                            int w) {
                                        Alarms.deleteAlarm(DeskClockMainActivity.this, id);
                                    }
                                })
                        .setNegativeButton(android.R.string.cancel, null)
                        .show();
                return true;

            case R.id.enable_alarm:
                final Cursor c = (Cursor) mAlarmsList.getAdapter()
                        .getItem(info.position);
                final Alarm alarm = new Alarm(c);
                Alarms.enableAlarm(this, alarm.id, !alarm.enabled);
                if (!alarm.enabled) {
                    SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
                            alarm.daysOfWeek);
                }
                return true;

            case R.id.edit_alarm:
                Intent intent = new Intent(this, SetAlarm.class);
                intent.putExtra(Alarms.ALARM_ID, id);
                startActivity(intent);
                return true;

            default:
                break;
        }
        return super.onContextItemSelected(item);
    }
    
    /*
     * (non-Javadoc)
     * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
     * 创建菜单
     */
    @Override
    public void onCreateContextMenu(ContextMenu menu, View view,
            ContextMenuInfo menuInfo) {
        // Inflate the menu from xml.
        getMenuInflater().inflate(R.menu.context_menu, menu);

        // Use the current item to create a custom view for the header.
        final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
        final Cursor c =
                (Cursor) mAlarmsList.getAdapter().getItem((int) info.position);
        final Alarm alarm = new Alarm(c);

        // Construct the Calendar to compute the time.
        final Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, alarm.hour);
        cal.set(Calendar.MINUTE, alarm.minutes);
        final String time = Alarms.formatTime(this, cal);

        // Inflate the custom view and set each TextView's text.
        final View v = mFactory.inflate(R.layout.context_menu_header, null);
        TextView textView = (TextView) v.findViewById(R.id.header_time);
        textView.setText(time);
        textView = (TextView) v.findViewById(R.id.header_label);
        textView.setText(alarm.label);

        // Set the custom view on the menu.
        menu.setHeaderView(v);
        // Change the text based on the state of the alarm.
        if (alarm.enabled) {
            menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm);
        }
    }
    
    /*
     * (non-Javadoc)
     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
     * 设置菜单的点击事件的处理
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_item_settings:
                startActivity(new Intent(this, SettingsActivity.class));
                return true;
            case R.id.menu_item_desk_clock:
            	//modify by wangxianming in 2012-4-14
//                startActivity(new Intent(this, DeskClock.class));
                return true;
            case R.id.menu_item_add_alarm:
                addNewAlarm();
                return true;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }
   
    /*
     * (non-Javadoc)
     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
     * 创建菜单
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.alarm_list_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    /*
     * (non-Javadoc)
     * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
     * 创建菜单的点击事件响应
     */
	public void onItemClick(AdapterView<?> adapterView, View v, int pos, long id) {
		Intent intent = new Intent(this, SetAlarm.class);
        intent.putExtra(Alarms.ALARM_ID, (int) id);
        startActivity(intent);
		
	}
	
   @Override
    protected void onDestroy() {
        super.onDestroy();
        ToastMaster.cancelToast();
        mCursor.close();
    }
}

【说明】想要源码的可以留下邮箱,我看到后就给你发过去!

也可以到我的csdn资源中下载:http://download.csdn.net/detail/wdaming1986/4226174

分享到:
评论

相关推荐

    基于Android 手机小闹钟源码

    【Android手机小闹钟源码】是一个典型的Android应用程序开发示例,主要展示了如何在Android平台上构建一个实用的小闹钟功能。对于想要深入学习Android开发,尤其是对系统级应用或者日常实用工具开发感兴趣的开发者来...

    Android 闹钟功能实例源码

    本实例源码提供了一个完整的Android闹钟功能的实现,旨在帮助开发者深入理解如何在自己的应用中集成这一功能。下面我们将详细探讨Android闹钟功能的实现原理以及源码中的关键部分。 一、Android闹钟服务概述 在...

    Android 闹钟源码

    本文将深入探讨Android 闹钟源码的工作原理、关键组件以及如何实现自定义闹钟应用。 首先,Android 闹钟功能的核心在于`AlarmManager`类,它是Android SDK中的一个系统服务,负责调度定时事件。`AlarmManager`可以...

    android 小闹钟源码

    以下是对"android小闹钟源码"的详细解析: 1. **Android应用程序基础**:Android应用由一系列组件构成,包括活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)和内容提供者(ContentProvider)...

    Android系统闹钟com.android.deskclock源码

    《深入解析Android系统闹钟com.android.deskclock源码》 Android系统闹钟,作为用户日常生活中不可或缺的一部分,其背后的实现原理与源码是许多开发者和技术爱好者关注的焦点。com.android.deskclock作为Android...

    Android 闹钟源码.zip

    《Android 闹钟应用源码解析》 在Android平台上的应用程序开发中,闹钟功能是一项基本且实用的功能,它能够帮助用户在设定的时间点得到提醒。Android 闹钟源码的分析,对于开发者来说,是深入理解系统底层机制、...

    Android 闹钟app 源码 可以自己设定时间 ,适配android 8,9,10,11

    本资源提供的"Android 闹钟app 源码"是一个适用于Android 8到11版本的源代码,非常适合学习和实践Android应用开发。以下是基于该源码可能涉及的主要知识点的详细解析: 1. **AlarmManager**: Android中的...

    android 自制闹钟源码

    以下将详细解析“android 自制闹钟源码”的相关知识点。 1. **BroadcastReceiver**: Android系统中的闹钟功能通常基于BroadcastReceiver。BroadcastReceiver是Android四大组件之一,用于接收和处理系统或应用程序...

    安卓Android源码——闹钟程序.zip

    这份“安卓Android源码——闹钟程序.zip”很可能是包含了实现此类应用的源代码,让我们来详细探讨一下其中可能涉及的关键知识点。 1. **AlarmManager**: 安卓中的`AlarmManager`服务是用于安排在特定时间执行一次性...

    android 4.0 桌面时钟源码DeskClock

    《Android 4.0 桌面时钟源码DeskClock深度解析》 在Android操作系统中,DeskClock是一款内置的桌面时钟应用,它集成了多种功能,包括时钟、闹钟、计时器和秒表。对于开发者来说,深入理解DeskClock的源码能够帮助...

    Android项目源码适合新手的简单闹钟项目蓝宝闹钟.zip

    《Android新手入门:解析“蓝宝闹钟”项目源码》 在移动开发领域,Android以其开源、灵活的特性吸引了大量的开发者。对于初学者来说,理解并实践Android项目源码是提升技能的重要途径。本文将深入探讨一个适合新手...

    安卓Android源码——Android自定义锁屏实现----仿正点闹钟.zip

    这个"安卓Android源码——Android自定义锁屏实现----仿正点闹钟.zip"压缩包文件提供了一个实例,展示了如何模仿“正点闹钟”的锁屏功能。通过分析和学习这个源码,我们可以了解到Android系统的锁屏机制以及如何进行...

    Android 精美愤怒的小闹钟源码.zip源码资源下载

    一、Android闹钟功能基础 Android系统中的闹钟功能主要由AlarmManager服务负责,它是系统级的服务,用于设置定时任务,比如定时启动应用、发送广播等。通过AlarmManager,开发者可以设置一次性或重复性的闹钟,同时...

    android 系统闹钟源码

    一、Android闹钟服务概述 Android系统中的闹钟服务主要由`AlarmManager`类提供,它负责调度和管理系统的定时事件。`AlarmManager`通过与系统内核的交互,确保在指定时间触发相应的闹钟事件。同时,开发者可以通过`...

    Android应用源码安卓闹钟简洁版注释详细

    通过研究这个源码,开发者不仅可以学习到如何构建一个基本的Android闹钟应用,还能深入理解Android系统的核心组件和工作原理。对于想要提升Android开发技能的人来说,这是一个非常有价值的实践项目。

    Android代码-闹钟源码.zip

    在Android平台上,开发一款闹钟应用涉及到多个关键知识点,...以上就是Android闹钟应用开发的主要知识点。通过对"闹钟源码.zip"的解压和分析,可以深入理解这些概念在实际代码中的实现方式,从而提升Android开发技能。

    Android 精美愤怒的小闹钟源码.rar

    《Android精美愤怒的小闹钟源码解析》 在Android应用开发领域,一款精美的小闹钟应用不仅能提供实用的功能,还能提升用户体验。"Android 精美愤怒的小闹钟源码"就是一个很好的实例,它展示了如何在Android平台上...

    Android代码-手机小闹钟源码.zip

    《Android手机小闹钟源码解析》 在Android开发领域,构建一款实用的手机小闹钟应用是一项常见的任务。这份“手机小闹钟源码”为我们提供了一个宝贵的实践案例,让我们深入理解Android应用开发的核心技术和设计思路...

    Android程序研发源码Android 精美愤怒的小闹钟源码.rar

    "Android程序研发源码Android 精美愤怒的小闹钟源码.rar" 这个标题表明这是一个关于Android应用开发的资源,具体来说是一个名为"AngryAlarm"的精美小闹钟应用的源代码。这个应用可能借鉴了愤怒的小鸟这款游戏的元素...

    安卓Android源码——闹钟+秒表+倒计时+时钟四合一源码.zip

    这篇文档将深入解析安卓Android平台上实现的"闹钟+秒表+倒计时+时钟四合一"的源码,帮助开发者理解如何在Android系统中集成这些常见的计时功能。我们将探讨以下几个方面: 1. **Android系统架构与计时器接口** ...

Global site tag (gtag.js) - Google Analytics