Android开发实战闹钟项目

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

推荐阅读