學習Android鬧鐘源代碼(三)-AlarmClock類分析(part1)

android的時鐘,也就是鬧鐘應用,從桌面的widget直接點進去的會打開AlarmClock這個Activity.java

好像我日常都不上圖的,今天就上兩張圖先。android

一張是應用界面圖以下:(改天再上傳了,好像今天osc服務器有問題啊)服務器

 

一,初看:ide

 總共有10個方法,加一個CursorAdapter的子類的內部類。佈局

 其中的10個方法以下:ui

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);

上面的方法不少都咱們比較熟悉的方法吧,呵呵,那就從比較熟悉的方法開始吧。this

(1) 也就是onItemClick()方法,代碼以下:.net

@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來顯示全部建立的鬧鐘。

當點擊某一個鬧鐘時,它將進入到鬧鐘的設置界面去:翻譯

上面的代碼的做用很顯然,code

先是所點擊鬧鐘的對應的Cursor對象,而後

經過Alarm類的構造方法,經過Cursor構造了一個Alarm實例。

Alarm類實現了Parcle,咱們能夠暫時將它只想像爲一個實體類,pojo之類的。

後面將詳細分析,或者你如今就去看看唄。呵呵。

而後,new出了Intent,將Alarm類做爲額外數據傳遞過去。上面還出現了Alarms類,

其實你能夠暫時把Alarms類想像爲Java Web開發常常用到的名字dao類,對了你就能夠這樣想Alarms=AlarmDao

呵呵。

而後它就啓動了SetAlarm這個Activity.

好了這個方法的任務完成。

 

(2)onCreateOptionsMenu()方法

當你按下Menu鍵時,就會調用這個方法,代碼以下;

@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()

代碼以下:

@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鍵時,只看到了[設置]這一菜單項。看下資源文件以下:

<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="@android :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();這個方法以下:

private void addNewAlarm() {
        startActivity(new Intent(this, SetAlarm.class));
 }

簡單到不能再簡單了,啓用鬧鐘設置界面。

 

(4)onCreateContextMenu()

ContextMenu顧名思義就是上下文菜單,在桌面應用中,咱們也許叫作右鍵菜單。在android中通常是

經過長按來觸發的菜單。

@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的佈局代碼貼在下面,以讓你們加深理解:

<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

代碼以下有點長,可是還算比較清晰吧:

@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的額外參數傳遞。

  

到這裏,文章也夠長了,,對於這個類有了一個基本的認識一些普通的代碼分析到這裏。

其它方法的分析仍是另外寫一篇吧。

相關文章
相關標籤/搜索