Android开发实战闹钟项目

本文实例为大家分享了Android实战闹钟项目的具体代码,供大家参考,具体内容如下

一、闹钟功能的介绍以及界面的展示

该闹钟是根据我们手机闹钟设计的一个简单的闹钟APP,其中包含时钟、闹钟、秒表和计时器功能。用户可以对闹钟添加和删除,可以对秒表计时、暂停和重置,对计时器可以暂停、计时、继续和重置等功能。

二、介绍系统的设计界面

闹钟的布局文件代码如下
由于该闹钟系统包含时钟、闹钟、计时器、秒表四个功能,所以只要在xml文件插入TabHost控件就能实现在手机上更加简洁地展示四个功能。后面只需要在TabHost中插入四个Tab用来切换展示的界面,具体的代码实现如下:

public class MainActivity extends AppCompatActivity {

    private TabHost mTabHost;
    private StopWatchView mStopWatchView;

    @Override
    public SharedPreferences getPreferences(int mode) {
        return super.getPreferences(mode);
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTabHost = (TabHost) findViewById(R.id.tabhost);
        mTabHost.setup();

        mTabHost.addTab(mTabHost.newTabSpec("tabTime").setIndicator("时钟").setContent(R.id.tabTime));
        mTabHost.addTab(mTabHost.newTabSpec("tabAlarm").setIndicator("闹钟").setContent(R.id.tabAlarm));
        mTabHost.addTab(mTabHost.newTabSpec("tabTimer").setIndicator("计时器").setContent(R.id.tabTimer));
        mTabHost.addTab(mTabHost.newTabSpec("tabStopWatch").setIndicator("秒表").setContent(R.id.tabStopWatch));

        mStopWatchView = (StopWatchView) findViewById(R.id.tabStopWatch);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mStopWatchView.onDestory();
    }
}

一、时钟功能

因为时钟功能中,只要显示当前的日期和时钟就可以了,所以只需要插入一个TextView用来显示日期时间就可以了。

xml文件中的代码(new 一个时钟类TimeView,把时钟一块的LinearLayout换成com.example.tsclock.TimeView)

 // 时钟
<com.example.tsclock.TimeView
     android:id="@+id/tabTime"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">

<TextView
       android:id="@+id/tvTime"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:textAppearance="?android:attr/textAppearanceLarge"
       android:gravity="center"/>
</com.example.tsclock.TimeView>

TimeView.java
要将时间显示到TabHost中,就必须先要获取其中的id,然后通过Calendar获取当前系统的时间,最后再每过1秒钟刷新一次,这样就能够再TextView中出现时间在不停的变化。

public class TimeView extends LinearLayout {

    private TextView tvTime;

    public TimeView(Context context) {
        super(context);
    }

    public TimeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public TimeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    // 在初始化之后进行的操作
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        tvTime = (TextView) findViewById(R.id.tvTime);

        // handler每秒执行一次
        timerHandler.sendEmptyMessage(0);

    }

    // 可见属性发生变化之后
    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == View.VISIBLE){ // 如果可见 则发送一个消息
            timerHandler.sendEmptyMessage(0);
        }else{                           //  如果不可见 移除所有的消息
            timerHandler.removeMessages(0);
        }
    }

    // 重新刷新时间
    private void refreshTime(){
        // 呈现一个时间对象
        Calendar c = Calendar.getInstance();
        // 获取时分秒
        tvTime.setText(String.format("%d:%d:%d",c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),c.get(Calendar.SECOND)));

    }

    private Handler timerHandler = new Handler() {

        public void handleMessage(android.os.Message msg){
            // 呈现出来
            refreshTime();

            // 如果可见 则刷新
            if (getVisibility() == View.VISIBLE){
                // 1000毫秒之后再制学校handlerMessage()方法
                timerHandler.sendEmptyMessageDelayed(0,1000);
            }
        }
    };

}

二、闹钟功能

闹钟功能就相对时钟功能就复杂很多了,因为这里需要对闹钟进行增加,删除等操作,而且可能需要展示多个闹钟的时间。所以这里需要用到有一个Button控件用来增加闹钟和一个ListView控件用来展示闹钟的时间。

xml代码

// 闹钟
<com.example.tsclock.AlarmView
        android:id="@+id/tabAlarm"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

 <ListView
       android:id="@+id/lvAlarmList"
       android:layout_width="match_parent"
       android:layout_weight="1"
       android:layout_height="0dp">
</ListView>

<Button
      android:id="@+id/btnAddAlarm"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="@string/add_alarm"
      android:textColor="#FFFFFF"
      android:background="@color/colorBlue" />

</com.example.tsclock.AlarmView>

闹钟类,AlarmView.java
需要判断时间到了需要触发事件,需要播放音乐和震动。所以播放音乐和震动放在另一个活动中(PlayAlarmAty.java )

public class AlarmView extends LinearLayout {

    private Button btnAddAlarm;

    private ListView lvAlarmList;

    private ArrayAdapter<AlarmData> mAdapter;

    private static final String KEY_ALARM_LIST = "alarmList";

    // 使用系统的闹钟服务
    private AlarmManager mAlarmManager;

    public AlarmView(Context context) {
        super(context);
        init();
    }

    public AlarmView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init(){
        // 使用闹钟服务设定闹钟
        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);

    }

    // 在初始化之后进行的操作
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        btnAddAlarm  = (Button)findViewById(R.id.btnAddAlarm);
        lvAlarmList = (ListView) findViewById(R.id.lvAlarmList);
                                                                     // 系统的简单资源
        mAdapter = new ArrayAdapter<AlarmView.AlarmData>(getContext(),android.R.layout.simple_list_item_1);
        // 设置Adapter
        lvAlarmList.setAdapter(mAdapter);
        // 读取已经存储在SharedPreferences中的数据
        readSavedAlarmList();

        btnAddAlarm.setOnClickListener(new View.OnClickListener() {// 添加闹钟的点击事件
            @Override
            public void onClick(View v) {
                addAlarm();
            }
        });

        // 删除闹钟
        lvAlarmList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view,final int position, long id) {
                new AlertDialog.Builder(getContext()).setTitle("操作选项").setItems(new CharSequence[]{"删除"}, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        switch (which){
                            case 0:
                                deleteAlarm(position);
                                break;
                            default:
                                break;
                        }
                    }
                }).setNegativeButton("取消",null).show();

                return true;
            }
        });

    }

    // 删除闹钟
    private void deleteAlarm(int position){
        AlarmData ad = mAdapter.getItem(position);
        // 把闹钟从闹钟列表移除
        mAdapter.remove(ad);
        saveAlarmList();
        // 移除闹钟
        mAlarmManager.cancel(PendingIntent.getBroadcast(getContext(),ad.getId(),new Intent(getContext(),AlarmReceiver.class),0));
    }

    // 添加闹钟
    private void addAlarm(){
        // 获取当前时间
        Calendar c = Calendar.getInstance();

        // 弹出一个时间的选择框
        new TimePickerDialog(getContext(), new TimePickerDialog.OnTimeSetListener() {
            // 设置时间
            @Override
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
                // 获取当前时间
                Calendar calendar = Calendar.getInstance();
                calendar.set(Calendar.HOUR_OF_DAY,hourOfDay); // 设置时
                calendar.set(Calendar.MINUTE,minute);   // 设置分钟
                calendar.set(Calendar.SECOND,0);  // 秒清零
                calendar.set(Calendar.MILLISECOND,0); // 毫秒值清零

                // 如果设置闹钟时间小于当前时间,则往后推一天
                Calendar currentTime = Calendar.getInstance();
                if (calendar.getTimeInMillis() <= currentTime.getTimeInMillis()){
                    calendar.setTimeInMillis(calendar.getTimeInMillis()+24*60*60*1000);
                }

                AlarmData ad = new AlarmData(calendar.getTimeInMillis());
                mAdapter.add(ad);

                //需要根据API版本来判断调用,从Android4.4(API19)开始,为了节能省电(减少系统唤醒和电池使用)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    mAlarmManager.setWindow(AlarmManager.RTC_WAKEUP,
                            ad.getTime(),
                            100, // 时间误差范围 100毫秒
                            PendingIntent.getBroadcast(getContext(), ad.getId(),
                                    new Intent(getContext(), AlarmReceiver.class), 0));

                } else {
                    mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                            ad.getTime(),
                            5*60*1000,
                            PendingIntent.getBroadcast(getContext(), ad.getId(),
                                    new Intent(getContext(), AlarmReceiver.class), 0));
                }

                saveAlarmList();
            }
        },c.get(Calendar.HOUR_OF_DAY),c.get(Calendar.MINUTE),true).show();
    }

    // 存储数据(存到SharedPreferences中)
    private void saveAlarmList(){
        SharedPreferences.Editor editor = getContext().getSharedPreferences(AlarmView.class.getName(),Context.MODE_PRIVATE).edit();

        // 存储数据(for循环遍历Adapter)
        StringBuffer sb = new StringBuffer();
        //getCount表示这个adapter里面有多少item,就是有多少闹钟
        for (int i = 0 ; i < mAdapter.getCount(); i++){
            sb.append(mAdapter.getItem(i).getTime()).append(",");
        }

        // 所有的值传进去之后 去掉最后的逗
        if (sb.length() > 1){
            String content = sb.toString().substring(0,sb.length()-1);
            editor.putString(KEY_ALARM_LIST,content);

            System.out.println(content);// 输出存储的闹钟数据
        }else {
            editor.putString(KEY_ALARM_LIST,null);
        }

        editor.commit();
    }

    // 读取已存的数据
    private void readSavedAlarmList(){
        // 获取到SharedPreferences(数据内容)
        SharedPreferences sp = getContext().getSharedPreferences(AlarmView.class.getName(),Context.MODE_PRIVATE);
        String content = sp.getString(KEY_ALARM_LIST,null);

        // 这里需要判断,不然没闹钟数据的时候会有空指针异常
        if (content != null){
            //这里取得每一个闹钟的time添加到数组里
            String[] timeStrings = content.split(",");
            // 遍历数组,把数据添加到mAdapter
            for (String string : timeStrings){
                mAdapter.add(new AlarmData(Long.parseLong(string)));
            }
        }
    }

    //闹钟的数据,用一个类要保存,这是常用的做法
    private static class AlarmData{

        private long time = 0;
        private String timeLabel = ""; // 在外界获取时间的标签的字符串
        private Calendar date;

        // 闹钟响起的时间
        public AlarmData(long time){
            this.time = time;

            date = Calendar.getInstance();
            date.setTimeInMillis(time);

            timeLabel = String.format("%d月%d日 %d:%d",
                    date.get(Calendar.MONTH)+1,
                    date.get(Calendar.DAY_OF_MONTH),
                    date.get(Calendar.HOUR_OF_DAY),
                    date.get(Calendar.MINUTE));

        }
        public AlarmData(String ad){
            this.timeLabel = ad;
        }
        public void setTime(long time){
            this.time = time;
        }

        public long getTime(){
            return time;
        }

        public void setTimeLable(String timeLable){
            this.timeLabel = timeLable;
        }

        @Override
        public String toString() {
            return getTimeLabel();
        }

        public String getTimeLabel() {
            return timeLabel;
        }

        //为了给每一个闹钟设定一个标识,方便取消闹钟的使用能知道是哪一个闹钟
        public int getId(){
            return (int) (getTime()/1000/60);
        }
    }
}

当触发事件发生时,我们就要播放我们之前准备的音乐了,但是怎么播放呢,这里我们就要用到mediaPlayer媒体播放器这个函数了,这个函数主要就是用来播放音乐或者动画等。当开始播放时,我们也需要弹出警告框,提醒用户去关闭闹钟,所以这里我们需要另外编写一个类,用来执行这些功能。

PlayAlarmAty类中有播放音乐,开启震动,弹出关闭闹钟的dialog。

public class PlayAlarmAty extends Activity {

    // 音乐播放器
    private MediaPlayer mMediaPlayer;
    private Vibrator vibrator;
    private PowerManager.WakeLock mWakelock;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE); // hide title
        Window win = getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        winParams.flags |= (WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

        // 播放闹钟铃声
        mMediaPlayer = MediaPlayer.create(this,R.raw.music); //使用create方式,创建MediaPlayer对象
        mMediaPlayer.setLooping(true); // 设置是否对播放的音乐进行循环播放
        mMediaPlayer.start();

        startVibrator();
        createDialog();
    }

    @Override
    protected void onPause() {
        super.onPause();
        finish();
        // 释放锁屏
        releaseWakeLock();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 唤醒屏幕
        acquireWakeLock();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mMediaPlayer.stop();
        mMediaPlayer.release(); // 释放掉
    }

    // 唤醒屏幕
    private void acquireWakeLock() {

        if (mWakelock == null) {
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
            mWakelock = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP
                    | PowerManager.SCREEN_DIM_WAKE_LOCK, this.getClass()
                    .getCanonicalName());
            mWakelock.acquire();
        }
    }

    // 释放锁屏
    private void releaseWakeLock() {
        if (mWakelock != null && mWakelock.isHeld()) {
            mWakelock.release();
            mWakelock = null;
        }
    }
    // 震动
    private void startVibrator() {
        // 想设置震动大小可以通过改变pattern来设定,如果开启时间太短,震动效果可能感觉不到
        vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
        long[] pattern = { 500, 1000, 500, 1000 }; // 停止 开启 停止 开启
        vibrator.vibrate(pattern, 0);
    }

    private void createDialog() {
        new AlertDialog.Builder(this)
                .setIcon(R.drawable.ic_clock)
                .setTitle("闹钟")
                .setMessage("闹钟时间到了!!!")
                .setPositiveButton("推迟10分钟", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        tenMRemind();
                        mMediaPlayer.stop();
                        vibrator.cancel();
                        finish();
                    }
                })
                .setNegativeButton("关闭", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton) {
                        mMediaPlayer.stop();
                        vibrator.cancel();
                        finish();
                    }
                }).create().show();
    }

    // 推迟10分钟提醒
    private void tenMRemind(){
        //设置时间
        Calendar calendar_now = Calendar.getInstance();

        calendar_now.setTimeInMillis(System.currentTimeMillis());
        calendar_now.set(Calendar.HOUR_OF_DAY, calendar_now.get(Calendar.HOUR_OF_DAY));
        calendar_now.set(Calendar.MINUTE, calendar_now.get(Calendar.MINUTE)+10);
        calendar_now.set(Calendar.SECOND, 0);
        calendar_now.set(Calendar.MILLISECOND, 0);

        //时间选择好了
        Intent intent = new Intent(this, AlarmReceiver.class);
        //注册闹钟广播
        PendingIntent sender = PendingIntent.getBroadcast(
                this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager am;
        am = (AlarmManager) this.getSystemService(this.ALARM_SERVICE);
        am.set(AlarmManager.RTC_WAKEUP, calendar_now.getTimeInMillis(), sender);
    }

}

但是要当时间到了启动这个活动,就需要一个接收器,接受这个事件,所以有需要另一个类AlarmReceiver。

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("闹钟执行了");

        // 闹钟执行一次就取消当前所执行的闹钟
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        // 取消闹钟
        am.cancel(PendingIntent.getBroadcast(context,getResultCode(),new Intent(context,AlarmReceiver.class),0));

        Intent i = new Intent(context,PlayAlarmAty.class); // 要启动的类
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 设置启动的模式
        context.startActivity(i);
    }
}

三、秒表功能

秒表功能包含四个功能键,分别为开始,暂停、继续和重置。所以需要四个Button,然后需要三个EditText分别用来给用户输入时分秒。具体的xml代码如下:

// 秒表
<com.example.tsclock.StopWatchView
      android:id="@+id/tabStopWatch"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical">

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="horizontal">
<TextView
       android:id="@+id/timeHour"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text=":"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
       android:id="@+id/timeMin"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text=":"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
       android:id="@+id/timeSec"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="."
      android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
       android:id="@+id/timeMSec"
       android:layout_width="0dp"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
 </LinearLayout>

<ListView
       android:id="@+id/lvWatchTime"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"/>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:orientation="horizontal">

<Button
        android:id="@+id/btnSWStart"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="@string/start"
        android:textColor="#FFFFFF"
        android:background="@color/colorBlue"/>

<Button
        android:id="@+id/btnSWPause"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="@string/pause"
        android:textColor="#FFFFFF"
        android:background="@color/colorBlue"/>

<Button
         android:id="@+id/btnSWResume"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:text="@string/resume"
         android:textColor="#FFFFFF"
         android:background="@color/colorBlue"/>

<Button
         android:id="@+id/btnSWLap"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:text="@string/lap"
        android:textColor="#FFFFFF"
        android:background="@color/colorBlue"/>

<Button
          android:id="@+id/btnSWReset"
          android:layout_width="0dp"
          android:layout_height="wrap_content"
          android:layout_weight="1"
          android:text="@string/reset"
          android:textColor="#FFFFFF"
         android:background="@color/colorBlue"/>
    </LinearLayout>
</com.example.tsclock.StopWatchView>

在秒表功能中,含有四个Button,但是有时候只要显示一个或者是两个其余的就需要隐藏,所以这里就需要用到Button中的属性setVisibility(View.GONE)或者是setVisibility(View.VISIBLE),这是用来隐藏和显示Button。

有时候我们需要考虑系统的健壮性,比如当我们输入大于59的数或者是小于0的数,这时候我们需要系统检测出来,并进行修正。

需要注意的就是,当我们修改计时的时间的时候,当我们不小心将数目清空的时候,这时候就会将空指针上传,导致系统的崩溃,所以我们需要判断是不是空指针,防止越界报错。

该秒表功能有五个Button,所以需要对每个Button添加触发事件,其实startTime()函数的功能为开始计时,stopTime()函数的功能为暂停计时。所以这里需要弄清楚的就是什么时候该让那些按钮隐藏,什么时候该让那些按钮显示。

public class StopWatchView extends LinearLayout {

    private TextView tvHour,tvMin,tvSec,tvMSec;

    private Button btnSWStart,btnSWResume,btnSWReset,btnSWLap,btnSWPause;

    private ListView lvTimeList;

    private ArrayAdapter<String> adapter;

    private Timer mTimer = new Timer();
    private TimerTask mTimerTask = null;
    private int tenMSec = 0;
    private TimerTask showTimerTask = null;

    private static final int MSG_WHAT_SHOW_TIME = 1;

    public StopWatchView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        tvHour = (TextView) findViewById(R.id.timeHour);
        tvHour.setText("0");
        tvMin = (TextView) findViewById(R.id.timeMin);
        tvMin.setText("0");
        tvSec = (TextView) findViewById(R.id.timeSec);
        tvSec.setText("0");
        tvMSec = (TextView) findViewById(R.id.timeMSec);
        tvMSec.setText("0");

        // 计时
        btnSWLap = (Button) findViewById(R.id.btnSWLap);
        btnSWLap.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                                                                   // 时         分               秒            毫秒
                adapter.insert(String.format("%d:%d:%d.%d",tenMSec/100/60/60,tenMSec/100/60%60,tenMSec/100%60,tenMSec%100),0);

            }
        });

        // 开始
        btnSWStart = (Button) findViewById(R.id.btnSWStart);
        btnSWStart.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                startTimer();

                btnSWStart.setVisibility(View.GONE);
                btnSWPause.setVisibility(View.VISIBLE);
                btnSWLap.setVisibility(View.VISIBLE);
            }
        });

        // 暂停
        btnSWPause = (Button) findViewById(R.id.btnSWPause);
        btnSWPause.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                stopTimer();

                btnSWPause.setVisibility(View.GONE);
                btnSWResume.setVisibility(View.VISIBLE);
                btnSWLap.setVisibility(View.GONE);
                btnSWReset.setVisibility(View.VISIBLE);
            }
        });

        // 继续
        btnSWResume = (Button) findViewById(R.id.btnSWResume);
        btnSWResume.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                startTimer();
                btnSWResume.setVisibility(View.GONE);
                btnSWPause.setVisibility(View.VISIBLE);
                btnSWReset.setVisibility(View.GONE);
                btnSWLap.setVisibility(View.VISIBLE);
            }
        });

        // 重置
        btnSWReset = (Button) findViewById(R.id.btnSWReset);
        btnSWReset.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                stopTimer();
                tenMSec = 0;
                adapter.clear();// 重置需要清除列表

                btnSWLap.setVisibility(View.GONE);
                btnSWPause.setVisibility(View.GONE);
                btnSWResume.setVisibility(View.GONE);
                btnSWReset.setVisibility(View.GONE);
                btnSWStart.setVisibility(View.VISIBLE);

            }
        });

        // 设置除了开始之外 其它四个按钮不可见
        btnSWLap.setVisibility(View.GONE);
        btnSWPause.setVisibility(View.GONE);
        btnSWResume.setVisibility(View.GONE);
        btnSWReset.setVisibility(View.GONE);

        lvTimeList = (ListView) findViewById(R.id.lvWatchTime);

        // 初始化话adapter
        adapter = new ArrayAdapter<String>(getContext(),android.R.layout.simple_list_item_1);
        lvTimeList.setAdapter(adapter);

        // 使用showTimerTask不断执行刷新的操作
        showTimerTask = new TimerTask() {
            @Override
            public void run() {
                handler.sendEmptyMessage(MSG_WHAT_SHOW_TIME);
            }
        };
        mTimer.schedule(showTimerTask,200,200); // 一秒钟刷新五次

    }

    private void startTimer(){
        if (mTimerTask == null){
            mTimerTask = new TimerTask() {// 计时的timerTask
                @Override
                public void run() {
                    tenMSec++;
                }
            };
            mTimer.schedule(mTimerTask,10,10); // 每隔十毫秒执行一次
        }
    }

    private void stopTimer(){
        if (mTimerTask != null){
            mTimerTask.cancel();
            mTimerTask = null;
        }
    }

    // 呈现时间的handler
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case MSG_WHAT_SHOW_TIME:
                    tvHour.setText(tenMSec/100/60/60+""); // 时
                    tvMin.setText(tenMSec/100/60%60+""); // 分
                    tvSec.setText(tenMSec/100%60+""); // 秒
                    tvMSec.setText(tenMSec%100+""); // 毫秒
                    break;
                default:
                    break;
            }
        }
    };

    public void onDestory() {
        mTimer.cancel();
    }
}

四、计时器功能

这个和上面讲了秒表比较类似,不同的是多一个Button按钮用来计时,还多一个EditView(毫秒值),另外还需要一个ListView用来显示计时的时间,详细的xml代码如下:

// 计时器
<com.example.tsclock.TimerView
        android:id="@+id/tabTimer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

<LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
<EditText
        android:id="@+id/etHour"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="number"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=":"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
<EditText
        android:id="@+id/etMin"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="number"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=":"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
<EditText
        android:id="@+id/etSec"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="number"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
</LinearLayout>

<LinearLayout
        android:id="@+id/btnGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

<Button
        android:id="@+id/btnStart"
        android:layout_width="0dp"
        android:text="@string/start"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="#FFFFFF"
        android:background="@color/colorBlue"/>
<Button
        android:id="@+id/btnPause"
        android:layout_width="0dp"
        android:text="@string/pause"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textColor="#FFFFFF"
        android:background="@color/colorBlue"/>
<Button
         android:id="@+id/btnResume"
         android:layout_width="0dp"
         android:text="@string/resume"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:textColor="#FFFFFF"
         android:background="@color/colorBlue"/>
<Button
         android:id="@+id/btnReset"
         android:layout_width="0dp"
         android:text="@string/reset"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:textColor="#FFFFFF"
         android:background="@color/colorBlue"/>
   </LinearLayout>
</com.example.tsclock.TimerView>

计时器功能和秒表功能差不多

public class TimerView extends LinearLayout {

    private Button btnStart,btnPause,btnResume,btnReset;
    private EditText etHour,etMin,etSec;

    private Timer mTimer = new Timer(); // 计时器
    private TimerTask mTimerTask = null;
    private int allTimerCount = 0;

    private static final int MSG_WHAT_TIME_IS_UP = 1;
    private static final int MSG_WHAT_TIME_IS_TICK = 2; // 时钟一格一格的往下走

    private ListView mListView;

    public TimerView(Context context) {
        super(context);
    }

    public TimerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        //开始
        btnStart = (Button) findViewById(R.id.btnStart);
        btnStart.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                startTimer();

                btnStart.setVisibility(View.GONE);
                btnPause.setVisibility(View.VISIBLE);
                btnReset.setVisibility(View.VISIBLE);
                etHour.setEnabled(false);
                etMin.setEnabled(false);
                etSec.setEnabled(false);

            }
        });

        // 暂停
        btnPause = (Button) findViewById(R.id.btnPause);
        btnPause.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                stopTimer();

                btnPause.setVisibility(View.GONE);
                btnResume.setVisibility(View.VISIBLE);
            }
        });

        // 继续
        btnResume = (Button) findViewById(R.id.btnResume);
        btnResume.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                startTimer();

                btnResume.setVisibility(View.GONE);
                btnPause.setVisibility(View.VISIBLE);
            }
        });

        // 重置
        btnReset = (Button) findViewById(R.id.btnReset);
        btnReset.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                stopTimer();

                etHour.setText("00");
                etMin.setText("00");
                etSec.setText("00");
                etHour.setEnabled(true);
                etMin.setEnabled(true);
                etSec.setEnabled(true);

                btnStart.setVisibility(View.VISIBLE);
                btnPause.setVisibility(View.GONE);
                btnResume.setVisibility(View.GONE);
                btnReset.setVisibility(View.GONE);
            }
        });

        etHour = (EditText) findViewById(R.id.etHour);
        etMin = (EditText) findViewById(R.id.etMin);
        etSec = (EditText) findViewById(R.id.etSec);

        etHour.setText("00");
        // 添加事件监听器
        etHour.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (!TextUtils.isEmpty(s)){
                    int value = Integer.parseInt(s.toString());
                    if (value > 59){
                        etHour.setText("59");
                    }else if (value < 0){
                        etHour.setText("0");
                    }
                }
                checkToEnableBtnStart();
            }
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }
            @Override
            public void afterTextChanged(Editable s) {

            }
        });
        etMin.setText("00");
        etMin.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (!TextUtils.isEmpty(s)){
                    int value = Integer.parseInt(s.toString());
                    if (value > 59){
                        etMin.setText("59");
                    }else if (value < 0){
                        etMin.setText("0");
                    }
                }
                checkToEnableBtnStart();
            }
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }
            @Override
            public void afterTextChanged(Editable s) {

            }
        });
        etSec.setText("00");
        etSec.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (!TextUtils.isEmpty(s)){ // 当文字框中不为空
                    int value = Integer.parseInt(s.toString());
                    if (value > 59){
                        etSec.setText("59");
                    }else if (value < 0){
                        etSec.setText("0");
                    }
                }
                checkToEnableBtnStart();
            }
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        btnStart.setVisibility(View.VISIBLE); // 设置开始可见
        btnStart.setEnabled(false); // 不可点击(开始还没有设置时间)
        btnPause.setVisibility(View.GONE); // 设置暂停不可见
        btnResume.setVisibility(View.GONE);
        btnReset.setVisibility(View.GONE);

    }

    private void checkToEnableBtnStart(){

        btnStart.setEnabled((!TextUtils.isEmpty(etHour.getText()) && Integer.parseInt(etHour.getText().toString()) > 0) ||
                (!TextUtils.isEmpty(etMin.getText()) &&Integer.parseInt(etMin.getText().toString()) > 0) ||
                (!TextUtils.isEmpty(etSec.getText()) &&Integer.parseInt(etSec.getText().toString()) > 0));
    }

    private void startTimer(){
        if (mTimerTask == null){
            // 所使用时间的计数
            allTimerCount = Integer.parseInt(etHour.getText().toString())*60*60+Integer.parseInt(etMin.getText().toString())*60+Integer.parseInt(etSec.getText().toString());
            mTimerTask = new TimerTask() {
                @Override
                public void run() { // run方法会被mTimer执行
                    // 每执行一次 计数减一
                    allTimerCount--;

                    // 获取到当
                    mHandler.sendEmptyMessage(MSG_WHAT_TIME_IS_TICK);

                    if (allTimerCount <= 0){
                        // 访问mHandler
                        mHandler.sendEmptyMessage(MSG_WHAT_TIME_IS_UP);
                        stopTimer();
                    }

                }
            };

            mTimer.schedule(mTimerTask,1000,1000); // run方法每隔一秒执行一次

        }
    }
    private void stopTimer(){
        if (mTimerTask != null){
            mTimerTask.cancel();
            mTimerTask = null;
        }
    }

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case MSG_WHAT_TIME_IS_TICK:
                    int hour = allTimerCount/60/60;
                    int min = (allTimerCount/60)%60;
                    int sec = allTimerCount%60;

                    etHour.setText(hour+"");
                    etMin.setText(min+"");
                    etSec.setText(sec+"");

                    break;
                case MSG_WHAT_TIME_IS_UP:
                    // 执行弹出对话框操作
                    // 把时间停止(弹出一个对话框)
                    new AlertDialog.Builder(getContext()).setTitle("时间到了!!!").setNegativeButton("退出",null).show();

                    btnPause.setVisibility(View.GONE);
                    btnResume.setVisibility(View.GONE);
                    btnReset.setVisibility(View.GONE);
                    btnStart.setVisibility(View.VISIBLE);
                    etHour.setEnabled(true);
                    etMin.setEnabled(true);
                    etSec.setEnabled(true);

                    break;
                default:
                    break;
            }
        }
    };
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2022-09-09

简单实现Android闹钟程序 附源码

这个应用实现了简单的闹钟功能,关闭程序的状态中也可以进行闹钟的提醒. 这里遗留了一个问题: 如果我通过应用本身关闭程序,是可以实现我上述所说的功能,但是如果我在手机进程管理中实现应用程序的关闭操作,这个提醒就不起作用了,我很疑惑的是,我通过应用程序本身关闭了后,在进程中也是查看不到这个应用了的.所以哪位知道的帮留个言指点下,谢谢. ClockDemo.java package com.example.clock; import java.util.Calendar; import android

Android编程实现闹钟的方法详解

本文实例讲述了Android编程实现闹钟的方法.分享给大家供大家参考,具体如下: 在Android中,有一个闹钟的类,AlarmManager类,我们可以通过其来对系统内的通知进行操作! 本文用到了Service和Broadcast两个后台管理,在处理时,曾出现过很多问题,但经过半天的努力,终于解决了! 首先是Main.xml文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns

Android实现简易闹钟功能

本文实例为大家分享了Android通过广播来实现闹钟的具体代码,供大家参考,具体内容如下 1.创建广播接收RepeatingAlarm.java import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class RepeatingAlarm extends BroadcastRe

Android闹钟机制实现定时任务功能

Android的闹钟实现机制, 需要调用AlarmManager.set()将闹铃时间记录到系统中,当闹铃时间到后,系统会给应用程序发送广播,我们只需要去注册广播接收器就可以了. 本文分三部分讲解如何实现闹钟: 目录: 1. 设置闹铃时间; 2. 接收闹铃事件广播; 3. 重开机后重新计算并设置闹铃时间; 1. 设置闹铃时间(毫秒) private void setAlarmTime(Context context, long triggerAtMillis) { AlarmManager am

Android闹钟设置的解决方案

Android设置闹钟并不像IOS那样这么简单,做过Android设置闹钟的开发者都知道里面的坑有多深.下面记录一下,我解决Android闹钟设置的解决方案. 主要问题 1.API19开始AlarmManager的机制修改. 2.应用程序被Kill掉后,设置的闹钟不响. 3.6.0以上进入Doze模式会使JobScheduler停止工作. 4.手机设置重启后,闹钟失效问题. API19以上AlarmManager机制的修改 API19之前AlarmManager提供了三个设置闹钟的方法,由于业务

Android通过AlarmManager类实现简单闹钟功能

Android通过AlarmManager类实现闹钟,供大家参考,具体内容如下 简介 闹钟是生活中最常用的功能了,很多App都可以加入该功能,提醒用户某个时刻要做的事情.在Android系统中可以通过AlarmManager类实现闹钟,AlarmManager类是专门用来设定在某个指定的时间去完成指定的事件.AlarmManager提供了访问系统警报的服务,只要在程序中设置了警报服务,AlarmManager就会通过onReceive()方法去还行这些事件,就算系统处于待机状态,同样不会影响运行

Android闹钟启动时间设置无效问题的解决方法

Android开发中,alarmManager在5.0以上系统,启动时间设置无效的问题 做一个app,需要后台保持发送心跳包.由于锁屏后CPU休眠,导致心跳包线程被挂起,所以尝试使用alarmManager定时唤醒Service发送心跳包. 以下是开启alarmManager的代码 //开启轮询服务 public static void startPollingService(Context context, int seconds, Class<?> cls,String action) {

简单实现Android闹钟功能

闹钟的简单实现,只有显示时间和设置闹钟. AlarmView package com.example.lenovo.clock2; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.TimePickerDialog; import android.content.Context; import android.content.DialogInterface; import a

Android手机闹钟用法实例

本文实例讲述了Android手机闹钟用法.分享给大家供大家参考.具体如下: 一.开发手机闹钟主要用到了AlarmManager类,AlarmManager类提供了访问系统定时服务的途径,开发人员可以在程序中设置某个应用程序在未来的某个时刻被执行.当AlarmManager定时时间到了之后,当初注册的Intent对象将会被系统广播,进而启动目标程序. 二.在程序运行时当需要使用AlarmManager类时,可以通过Context对象的getSystemService(Context.ALARM_S

Android编程闹钟设置方法详解

本文实例讲述了Android编程闹钟设置方法.分享给大家供大家参考,具体如下: 闹钟在生活中最常见了,在Android中可以通过AlarmManager来实现闹钟,AlarmManager类专门用来设置在某个指定的时间去完成指定的时间.AlarmManager就会通过onReceive()方法去执行这些事件,就算系统处于待机状态,同样不会影响运行.可以通过Context.getSystemService方法来获得该服务.AlarmManager中的方法不少,如下: 方法 说明 Cancel 取消

Android编程解析XML方法详解(SAX,DOM与PULL)

本文实例讲述了Android编程解析XML方法.分享给大家供大家参考,具体如下: XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能.今天就由我向大家介绍一下在Android平台下几种常见的XML解析和创建的方法. 在Android中,常见的XML解析器分别为SAX解析器.DOM解析器和PULL解析器,下面,我将一一向大家详细介绍. SAX解析器: SAX(Simple API for XML)解析器是一种基于事

Android中SQLite 使用方法详解

Android中SQLite 使用方法详解 现在的主流移动设备像android.iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧.对于Android平台来说,系统内置了丰富的API来供开发人员操作SQLite,我们可以轻松的完成对数据的存取. 下面就向大家介绍一下SQLite常用的操作方法,为了方便,我将代码写在了Activity的onCreate中: @Ov

Android 中 onSaveInstanceState()使用方法详解

Android 中 onSaveInstanceState()使用方法详解 覆盖onSaveInstanceState方法,并在onCreate中检测savedInstanceState和获取保存的值 @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("currentposition", videoView.getCurrentPosition()); super.onSave

Android Parcelable接口使用方法详解

 Android Parcelable接口使用方法详解 1. Parcelable接口 Interface for classes whose instances can be written to and restored from a Parcel. Classes implementing the Parcelable interface must also have a static field called CREATOR, which is an object implementin

Android StringBuffer的使用方法详解

今天,讲讲StringBuffer的使用. StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类. 所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入.删除等操作,使用StringBuffer要更加适合一些. 在StringBuffer类中存在很多和String类一样的方法,这些方法在功能上和String类中的功能

Linux环境下Oracle安装参数设置方法详解

前面讲了虚拟机的设置和OracleLinux的安装,接下来我们来说下Oracle安装前的准备工作. 1.系统信息查看 系统信息查看 首先服务器ip:192.168.8.120 服务器系统:Oracle Linux Server release 6.5 服务器主机名:oracle-learn 查看磁盘空间情况: [root@oracle-learn ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 32G 4.8G 26G

Android编程之光线传感器用法详解

本文实例讲述了Android编程之光线传感器用法.分享给大家供大家参考,具体如下: Android手机自带光线传感器,通常我们手机的屏幕自动亮度都是用光线传感器来实现的.该传感器在前置摄像头附近,此外,还有一个距离传感器.这里主要讲解如何使用Android手机的光线传感器. 获得感应器服务 Android开发中要使用光线传感器,需要先获得系统传感器服务Context.SENSOR_SERVICE,获得方法如下: SensorManager senserManager = (SensorManag

Android编程自定义组件实例详解

本文实例讲述了Android编程自定义组件.分享给大家供大家参考,具体如下: 在Android中,所有的UI界面都是由View类和ViewGroup类及其子类组合而成.其中,View类是所有UI组件的基类,而ViewGroup类是容纳这些UI组件的容器. 其本身也是View类的子类. 在实际开发中,View类还不足以满足程序所有的需求.这时,便可以通过继承View类来开发自己的组件. 开发自定义组件的步骤: 1.创建一个继承android.view.View类的View类,并且重写构造方法. 2