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

(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, );
//获取闹钟的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() != ) {
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() != ) {
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 == -) {
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();
}
}

Android 闹钟最终版的更多相关文章

  1. 最终版的Web(Python实现)

    天啦,要考试了,要期末考试了,今天把最终版的Python搭建Web代码先写这里记下了.详细的过程先不写了. 这次是在前面的基础上重写 HTTPServer 与 BaseHTTPRequestHandl ...

  2. Angular 2 最终版正式发布

    9月15日,Angular 2 的最终版正式发布了. 作为 Angular 1 的全平台继任者 -- Angular 2 的最终版,意味着什么? 意味着稳定性已经得到了大范围用例的验证: 意味着已经针 ...

  3. RHEL 6.0服务器安装Oracle 11G R2 最终版

    RHEL6安装Oracle 11g R2最终版 结合网上教程 服务器实战所得 1.使用DVD做yum源新建dvd挂载目录[root@fxq-dp ~]# mkdir /media/iso进入到DVD挂 ...

  4. Android闹钟 AlarmManager的使用

    Android闹钟 AlarmManager的使用 AlarmManager介绍 AlarmManager这个类提供对系统闹钟服务的访问接口. 你可以为你的应用设定一个在未来某个时间唤醒的功能. 当闹 ...

  5. Android闹钟设置的解决方案

    Android设置闹钟并不像IOS那样这么简单,做过Android设置闹钟的开发者都知道里面的坑有多深.下面记录一下,我解决Android闹钟设置的解决方案. 主要问题 API19开始AlarmMan ...

  6. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

  7. jQuery 3.0最终版发布,十大新特性眼前一亮

    jQuery 3.0在日前发布了最终的全新版本.从2014年10月,jQuery团队对这个主要大版本进行维护开始,web开发者社区便一直在期待着这一刻的到来,终于在2016年6月他们迎来了这一个最终板 ...

  8. Android P正式版即将到来:后台应用保活、消息推送的真正噩梦

    1.前言 对于广大Android开发者来说,Android O(即Android 8.0)还没玩热,Andriod P(即Andriod 9.0)又要来了.   下图上谷歌官方公布的Android P ...

  9. Delphi7/2007/2009/2010/XE/XE2/XE3/XE4/XE5/XE6/XE7/XE8/10最终版

    RAD Studio 10.1 Berlin(with Update1)http://altd.embarcadero.com/download/radstudio/10.1/delphicbuild ...

随机推荐

  1. startActivityForResult()的用法

    举例说我想要做的一个事情是,在一个主界面(主Activity)上能连接往许多不同子功能模块(子Activity上去),当子模块的事情做完之后就回到主界面,或许还同时返回一些子模块完成的数据交给主Act ...

  2. 为您的Office文档加把锁-ADRMS的安装

    为您的Office文档加把锁-ADRMS的安装 如今不少企业越来越重视自己KM(知识管理系统)的建立对于KM的建立实施虽然可以有效地解决企业在知识管理上的问题对于一些具有商业利益关系的机密文件(例如: ...

  3. js-YDUI 移动端解决方案

    /** * YDUI 可伸缩布局方案 * rem计算方式:设计图尺寸px / 100 = 实际rem 例: 100px = 1rem */ !function (window) { /* 设计图文档宽 ...

  4. CF-833B The Bakery(线段树优化Dp)

      Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought required ingredie ...

  5. Linux系列-安装经常使用软件

    安装JDK: 理论篇: 一.下载JDK 二.安装 ①复制到/usr/java/路径下 [plain] view plaincopy #mkdir /usr/java/ #cp jdk-7u25-lin ...

  6. x264代码剖析(三):主函数main()、解析函数parse()与编码函数encode()

    x264代码剖析(三):主函数main().解析函数parse()与编码函数encode() x264的入口函数为main().main()函数首先调用parse()解析输入的參数,然后调用encod ...

  7. node中间层

    node中间层 一.总结 1.node中间层作用:前端也是mvc,NodeJS之后,前端可以更加专注于视图层,而让更多的数据逻辑放在Node层处理 2.node中间层作用:当发现所有请求量太多应付不过 ...

  8. mysql中配置ssl_key、ssl-cert、ssl-ca的路径及建立ssl连接(适用于5.7以下版本,5.7及以上请看本文末尾的备注)

    1.创建 CA 私钥和 CA 证书 (1)下载并安装openssl,将bin目录配置到环境变量: (2)设置openssl.cfg路径(若不设置会报错,找不到openssl配置文件) \bin\ope ...

  9. VUE笔记 - 过滤器 Vue.filter 形参默认值 @keyup.f2 自定义按键修饰符

    过滤器函数的传参: 第一个参数 A 是固定的,表示要过滤之前的内容. 第二个参数 B,表示要把原本的内容 A 过滤成 B. 写函数内容时, 这里第二处只写个参数. 实际的值要写到管道符调用函数的括号内 ...

  10. Oracle自定义类型在C#中调用示例

    1.C#代码: 1)using Oracle.DataAccess.Types; using System; using System.Collections.Generic; using Syste ...