我以前写了个复杂闹钟的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做的是允许别的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

 

 

 

      

更多相关文章

  1. Android——RecyclerView.scrollBy源码分析
  2. Android 菜单项选项
  3. android studio项目嵌入到Android系统源码
  4. Handler源码详解及导致内存泄漏的分析
  5. Android系统基础(02) 系统源码环境搭建
  6. 如何将android2.1源码添加到自己的项目当中
  7. android源码下载备注

随机推荐

  1. android NDK扩展
  2. JAVA效率真的很低吗?Android为什么要采用
  3. 我的第一个Android软件——简单拨号器
  4. 如何导入android 自带的例子
  5. android 配置ADB环境
  6. Android仿微信聊天界面
  7. 在Android使用正则表达式
  8. 更改android开机画面 DIY
  9. 【腾讯Bugly干货分享】Android进程保活招
  10. Android如何解析Intent Filter