android的时钟,也就是闹钟应用,从桌面的widget直接点进去的会打开AlarmClock这个Activity.
好像我平常都不上图的,今天就上两张图先。
一张是应用界面图如下:(改天再上传了,好像今天osc服务器有问题啊)
一,初看:
总共有10个方法,加一个CursorAdapter的子类的内部类。
其中的10个方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
private
void
updateAlarm(
boolean
enabled,Alarm alarm);
public
boolean
onContextItemSelected(
final
MenuItem item);
@Override
protected
void
onCreate(Bundle icicle);
private
void
updateLayout();
private
void
addNewAlarm();
private
void
onDestory();
public
void
onCreateContextMenu(ContextMenu menu,View view,
ContextMenuInfo menuInfo);
public
boolean
onOptionsItemSelected(MenuItem item);
public
boolean
onCreateOptionsMenu(Menu menu);
public
void
onItemClick(AdapterView parent,View v
int
pos,
long
id);
|
上面的方法很多都我们比较熟悉的方法吧,呵呵,那就从比较熟悉的方法开始吧。
(1) 也就是onItemClick()方法,代码如下:
1
2
3
4
5
6
7
8
9
|
@Override
public
void
onItemClick(AdapterView parent, View v,
int
pos,
long
id) {
final
Cursor c = (Cursor) mAlarmsList.getAdapter()
.getItem(pos);
final
Alarm alarm =
new
Alarm(c);
Intent intent =
new
Intent(
this
, SetAlarm.
class
);
intent.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
startActivity(intent);
}
|
AlarmClock使用一个ListView加+CursorAdapter来显示所有创建的闹钟。
当点击某一个闹钟时,它将进入到闹钟的设置界面去:
上面的代码的作用很显然,
先是所点击闹钟的对应的Cursor对象,然后
通过Alarm类的构造方法,通过Cursor构造了一个Alarm实例。
Alarm类实现了Parcle,我们可以暂时将它只想像为一个实体类,pojo之类的。
后面将详细分析,或者你现在就去看看呗。呵呵。
然后,new出了Intent,将Alarm类作为额外数据传递过去。上面还出现了Alarms类,
其实你可以暂时把Alarms类想像为Java Web开发经常用到的名字dao类,对了你就可以这样想Alarms=AlarmDao
呵呵。
然后它就启动了SetAlarm这个Activity.
好了这个方法的任务完成。
(2)onCreateOptionsMenu()方法
当你按下Menu键时,就会调用这个方法,代码如下;
1
2
3
4
5
|
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.alarm_list_menu, menu);
return
super
.onCreateOptionsMenu(menu);
}
|
代码很简单两行,
第一行:获得菜单构造器,然后通过R.menu.alarm_list_menu菜单资源文件构造菜单。
第二行:子类应用父类的基本实现。
默认实现中将以标准的系统菜单项来填充menu,他们被归为CATEGORY_SYSTEM组,所以他们会以应用定义菜单项正确的排列。
(3)onOptionsItemSelected()
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@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:
startActivity(
new
Intent(
this
, DeskClock.
class
));
finish();
return
true
;
case
R.id.menu_item_add_alarm:
addNewAlarm();
return
true
;
case
android.R.id.home:
finish();
return
true
;
default
:
break
;
}
return
super
.onOptionsItemSelected(item);
}
|
事实在应用中,按下Menu键时,只看到了[设置]这一菜单项。看下资源文件如下:
1
2
3
4
5
6
7
8
9
10
|
<menu xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<item android:id=
"@+id/menu_item_add_alarm"
android:title=
"@string/add_alarm"
android:icon=
"@drawable/ic_menu_add"
android:showAsAction=
"always"
/>
<item android:id=
"@+id/menu_item_settings"
android:title=
"@string/settings"
android:icon=
"<a href="
http:
//my.oschina.net/asia" class="referer" target="_blank">@android</a> :drawable/ic_menu_preferences"
android:showAsAction=
"never"
/>
</menu>
|
注意到android:showAsAction=“always“
所以,这个菜单在ActionBar中显示了。
注意到 android.R.id.home这个是android4中内置的用于返回的menuItem吗?需要更多了解。
另外重要的一项R.id.menu_item_add_alarm就是添加闹钟了。它是作为ActionBar中的Action一直在显示。也是我们将主要关注的。
addNewAlarm();这个方法如下:
1
2
3
|
private
void
addNewAlarm() {
startActivity(
new
Intent(
this
, SetAlarm.
class
));
}
|
简单到不能再简单了,启用闹钟设置界面。
(4)onCreateContextMenu()
ContextMenu顾名思义就是上下文菜单,在桌面应用中,我们也许叫做右键菜单。在android中一般是
通过长按来触发的菜单。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
@Override
public
void
onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) {
// 从资源文件中上构造菜单Inflate the menu from xml.
getMenuInflater().inflate(R.menu.context_menu, menu);
// 使用当前项来创建一个自定义view来作为头
// Use the current item to create a custom view for the header.
final
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
// 获得当前项对应Curosr,通过Cursor构造Alarm对象
final
Cursor c =
(Cursor) mAlarmsList.getAdapter().getItem(info.position);
final
Alarm alarm =
new
Alarm(c);
// 构造Calendar对象来计算时间
// 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);
// 构造自定义View,并为每一个TextView设置显示文本 。
// 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);
}
}
|
代码比较简单,而且我也已经在代码中注释了,也保留了原本的英文注释。呵呵,我基本只是翻译呢。
现在再把context_menu_header的布局代码贴在下面,以让大家加深理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"match_parent"
android:layout_height
=
"wrap_content"
android:paddingTop
=
"6dip"
android:paddingBottom
=
"9dip"
android:paddingLeft
=
"10dip"
android:paddingRight
=
"10dip"
>
<
ImageView
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_gravity
=
"top"
android:paddingTop
=
"6dip"
android:paddingRight
=
"10dip"
android:src
=
"@drawable/ic_dialog_time"
/>
<
TextView
android:id
=
"@+id/header_time"
style
=
"?android:attr/textAppearanceLarge"
android:layout_width
=
"wrap_content"
android:layout_height
=
"match_parent"
android:singleLine
=
"true"
android:gravity
=
"center_vertical"
android:ellipsize
=
"none"
/>
<
TextView
android:id
=
"@+id/header_label"
style
=
"?android:attr/textAppearanceLarge"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:layout_marginLeft
=
"20dip"
android:singleLine
=
"true"
android:gravity
=
"right|center_vertical"
android:ellipsize
=
"end"
/>
</
LinearLayout
>
|
(5)这一个自然就是,onContextItemSelected
代码如下有点长,但是还算比较清晰吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
@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(AlarmClock.
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: {
final
Cursor c = (Cursor) mAlarmsList.getAdapter()
.getItem(info.position);
final
Alarm alarm =
new
Alarm(c);
Intent intent =
new
Intent(
this
, SetAlarm.
class
);
intent.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
startActivity(intent);
return
true
;
}
default
:
break
;
}
return
super
.onContextItemSelected(item);
}
|
首先是从菜单项对象中获得AdapterContextMenuInfo类对象实例info
然后通过这个info获得Alarm实例id
然后做了个以防万一的错误检查。
接着对item的id值做了switch.
情况1 :用户选择了删除此闹钟
弹出一个对话框,让用户确定是否删除。如果用户确定删除。
调用Alarms.deleteAlarm(context,id)删除。
情况2:用户选择了启用/停用闹钟
通过info获得position值从而从list的Adpater中获得对应的Cursor对象。
通过Cursor构造Alarm对象。
更新闹钟状态 Alarms.enableAlarm(this,alarm.id,!alarm.enabled)
如果闹钟之前是停用状态,那么弹出一个Toast,告诉用户闹钟什么时候会响。
情况3:用户选择了编辑些闹钟
构造出闹钟对应的Alarm对象。
然后启动闹钟设置界面,并将此Alarm作为Intent的额外参数传递。
到这里,文章也够长了,,对于这个类有了一个基本的认识一些普通的代码分析到这里。
其它方法的分析还是另外写一篇吧。