首页 > 代码库 > Android 闹钟最终版

Android 闹钟最终版

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

   (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, 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();    }}

 

Android 闹钟最终版