您的位置:首页 > 移动开发 > Android开发

android 闹钟的实现

2014-08-11 14:58 141 查看
转载 /article/1393495.html


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

分类: android源码解析2012-04-14
18:14 43973人阅读 评论(484) 收藏 举报

androidAndroidserviceService玲闹钟闹钟源码

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

转载请标明出处:/article/1393495.html

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

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

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

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

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

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

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

[java] view
plaincopyprint?

// 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这个服务的定义如下:

[java] view
plaincopyprint?

<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事件”。关键代码如下:

[java] view
plaincopyprint?

<span style="font-size:18px;"> @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);

}</span>

下面看看我的程序截图:

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





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





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

DeskClockMainActivity.java

[java] view
plaincopyprint?

<span style="font-size:18px;">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();

}

}</span>

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

也可以到我的csdn资源中下载:http://download.csdn.net/detail/wdaming1986/4226174
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: