学习Android闹钟源代码(三)-AlarmClock类分析(part1)

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的额外参数传递。

  

到这里,文章也够长了,,对于这个类有了一个基本的认识一些普通的代码分析到这里。

其它方法的分析还是另外写一篇吧。


?
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序邦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值