Android实战第一篇——时钟+闹钟+计时器+秒表
Posted Felix皇子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android实战第一篇——时钟+闹钟+计时器+秒表相关的知识,希望对你有一定的参考价值。
学习了快一学期的android了,之前的知识点都是零散的学习的,只有当我们真正的去把他们用起来的时候才会发现难点,自己才会独立尝试去解决某个问题。接下来是我的一个简单的多功能时钟的小实战(视频资源https://pan.baidu.com/s/1mL8VUVC-9W9lO6IEpobDZg 密码:2ajv)
具体的效果可以参考手机上的时钟。
首先我们来看一看布局文件layout_main.xml
我们总的来看一下整个布局
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.clock.TimeView
android:id="@+id/tabTime"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</com.example.clock.TimeView>
<com.example.clock.AlarmView
android:id="@+id/tabAlarm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<span style="white-space:pre"> </span>……
</com.example.clock.AlarmView>
<com.example.clock.TimerView
android:id="@+id/tabTimer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<span style="white-space:pre"> </span>……
</com.example.clock.TimerView>
<com.example.clock.StopWatchView
android:id="@+id/tabStopWatch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<span style="white-space:pre"> </span>……
</com.example.clock.StopWatchView>
</FrameLayout>
</LinearLayout>
</TabHost>
</FrameLayout>
整个布局整的是一个FrameLayout,我们在里面放了一个TabHost,接下来我们就可以在里面直接添加自己想要的布局了,可能初学者初一看会有那么一个疑问,就是<com.example.clock.……></com.example.clock.……>这个是什么东西??这是一个自定义的控件,我们创建的一个继承了LinearLayout的一个类(讲解可以参考这里http://blog.csdn.net/guozh/article/details/7662374),上面我们看到了四个这样的标签,表示我们有四个这样的Tab页面。关于布局的东西这里就不多讲了,之后会把我自己在学习过程中的一些不懂,以及相关的知识点上传到资源中,大家可以下载来看看。
这是完整的布局文件代码
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TabHost
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TabWidget>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.clock.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="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge" />
</com.example.clock.TimeView>
<com.example.clock.AlarmView
android:id="@+id/tabAlarm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lvListAlarm"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</ListView>
<Button
android:id="@+id/btnAddAlarm"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/add_alarm" >
</Button>
</com.example.clock.AlarmView>
<com.example.clock.TimerView
android:id="@+id/tabTimer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal" >
<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="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/btnStart"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/start" />
<Button
android:id="@+id/btnPause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/pause" />
<Button
android:id="@+id/btnResume"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/resume" />
<Button
android:id="@+id/btnReset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/reset" />
</LinearLayout>
</com.example.clock.TimerView>
<com.example.clock.StopWatchView
android:id="@+id/tabStopWatch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_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="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</ListView>
<LinearLayout
android:layout_width="fill_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" />
<Button
android:id="@+id/btnSWPause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/pause" />
<Button
android:id="@+id/btnSWResume"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/resume" />
<Button
android:id="@+id/btnSWLap"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/lap" />
<Button
android:id="@+id/btnSWReset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/reset" />
</LinearLayout>
</com.example.clock.StopWatchView>
</FrameLayout>
</LinearLayout>
</TabHost>
</FrameLayout>
讲完了布局,我们来讲讲MainActivity
private TabHost tabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabHost = (TabHost) findViewById(android.R.id.tabhost);
tabHost.setup();
// 为TabHost添加标签
// 新建一个newTabSpec(newTabSpec)用来指定该标签的id(就是用来区分标签)的
// 设置其标签和图表(setIndicator)
// 设置内容(setContent)
/*
* 设置选项卡 : -- 设置按钮名称 : setIndicator(时钟); -- 设置选项卡内容 : setContent(),
* 可以设置视图组件, 可以设置Activity, 也可以设置Fragement;
*/
tabHost.addTab(tabHost.newTabSpec("tabTime").setIndicator("时钟")
.setContent(R.id.tabTime));
tabHost.addTab(tabHost.newTabSpec("tabAlarm").setIndicator("闹钟")
.setContent(R.id.tabAlarm));
tabHost.addTab(tabHost.newTabSpec("tabTimer").setIndicator("计时器")
.setContent(R.id.tabTimer));
tabHost.addTab(tabHost.newTabSpec("tabStopWatch").setIndicator("秒表")
.setContent(R.id.tabStopWatch));
}
在MainActivity中主要的操作就是设置TabHost,上面的代码中已经贴上了解释,这里就不讲了,接着我们就重点来讲讲时钟、闹钟、计时器和秒表这四部分。
一、时钟
在布局文件中我们看到,界面上只有一个TextView,这个TextView的作用就是显示一个系统的当前时间,同时这个时间还是一秒一秒跳的,要实现一秒一秒的跳就需要我们每隔一秒就要刷新一下,同时我们这里还考虑了切换到另一个Tab的时候,这个时间就不跳动了,这样就会减少这个对系统的占用,考虑到了这点我们在这里用到了Handler,通过handler发送的msg.what 来判断是否要刷新时间。
public class TimeView extends LinearLayout {
private TextView tvTime;
public TimeView(Context context) {
super(context);
}
public TimeView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TimeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
tvTime = (TextView) findViewById(R.id.tvTime);
//tvTime.setText("hello");
timeHandler.sendEmptyMessage(0);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
//当再次切换到这个Tab时我们就再发送一次这个消息,否者就把所有的消息移除掉
if (visibility == View.VISIBLE) {
timeHandler.sendEmptyMessage(0);
}else{
timeHandler.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 timeHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
refreshTime();
//处于当前Tab的时候给自己发送信息,可以刷新
if (getVisibility() == View.VISIBLE) {
//1秒钟后再次执行以下sendEmptyMessage,what参数用于区分不同的message
timeHandler.sendEmptyMessageDelayed(0, 1000);
}
};
};
}
其实这里的Handler可以用Timer来完成亦可以达到同样的效果。
在这里要提一下的是onFinishInflate(),这在我们自定义布局的时候一定要用到的,解释以及例子在之后上传的知识点中同样有,看看那个就可以了。
二、闹钟
从第二个布局中我们可以看到,我们在这里用到了一个ListView,这是用来存储我们添加的闹钟的,既然这里用到了ListView,那么我们接着就会想到要给这个ListView一个适配器adapter,因此我们会在这里创建这么一个适配器,
private ArrayAdapter<AlarmData> adapter;
看到这里可能又会有疑问了,AlarmData这是个什么东西?有这么一个数据类型吗??其实这里我们自定义了一个数据类型,用来专门存储一下创建的闹钟时间。我们来看一下自定义的数据类型代码吧!
// 自定义数据类型
private static class AlarmData {
private long time = 0;
private Calendar date;
private String timeLabel = "";
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 long getTime() {
return time;
}
public String getTimeLabel() {
return timeLabel;
}
public int getId() {
return (int) (getTime() / 1000 / 60);
}
@Override
public String toString() {
return getTimeLabel();
}
}
这个数据类型的代码其实还是很容易明白的,不多讲了。
当我们到这里的时候,我们其实还没有真正的完成,假如我们的代码已经写好了,并且可以运行了我们运行一次后,并且添加了N个闹钟,当我们退出程序,再次打开就会发现,我们之前创建的闹钟都没了,原因是我们虽然把数据临时的保存在了ListView中,但是我们并没有长时间的保存,因此我们接着就来讲讲长久的保存这些闹钟数据。
private void saveAlarmList() {
Editor editor = getContext().getSharedPreferences(
AlarmView.class.getName(), Context.MODE_PRIVATE).edit();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < adapter.getCount(); i++) {
sb.append(adapter.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 readSaveAlarmList() {
SharedPreferences sp = getContext().getSharedPreferences(
AlarmView.class.getName(), Context.MODE_PRIVATE);
String content = sp.getString(KEY_ALARM_LIST, null);
if (content != null) {
String[] timeStrings = content.split(",");
for (String string : timeStrings) {
adapter.add(new AlarmData(Long.parseLong(string)));
}
}
}
上面的一些陌生的类型在之后的知识点中可以查看。
接着我们来看看最关键的就是添加闹钟
private void addAlarm() {
Calendar c = Calendar.getInstance();
new TPDiolog(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 (currentTime.getTimeInMillis() >= calendar.getTimeInMillis()) {
calendar.setTimeInMillis(calendar.getTimeInMillis() + 24
* 60 * 60 * 1000);
}
AlarmData ad = new AlarmData(calendar.getTimeInMillis());
adapter.add(ad);
alarmManager.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();
}
这里我们可以看到TPDiolog这个,当你自己尝试过后可能也会遇到同样的问题,那就是当你通过TimePickerDialog这个系统的时间选择控件的时候,点击确定后,会创建两条记录,这是因为我们点击确定后会调用该事件监听器的时间,在关闭这个Dialog的时候也会调用一次,所以我们在这里自己重写了一下该类的方法
TPDiolog.class
public class TPDiolog extends TimePickerDialog {
public TPDiolog(Context context, OnTimeSetListener callBack, int hourOfDay,
int minute, boolean is24HourView) {
super(context, callBack, hourOfDay, minute, is24HourView);
}
//重写该方法是为了避免调用两次onTimeSet
//可以参考 该网址http://www.68idc.cn/help/buildlang/ask/20150206210559.html
@Override
protected void onStop() {
//super.onStop();
}
}
在之前的代码中我们还看到了一个alarmManager这一对象,这是我们为了调用系统的闹钟服务创建的实例,我们也因此而创建了一个AlarmReceiver.class
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent arg1) {
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);
//设置intent的启动模式
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
一些小的地方讲好了,最后把AlarmView.class的完整代码贴上。
package com.example.clock;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.TimePicker;
public class AlarmView extends LinearLayout {
private Button btnAddAlarm;
private ListView lvListAlarm;
private ArrayAdapter<AlarmData> adapter;
private AlarmManager alarmManager;
public AlarmView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public AlarmView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AlarmView(Context context) {
super(context);
init();
}
private void init() {
alarmManager = (AlarmManager) getContext().getSystemService(
Context.ALARM_SERVICE);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
btnAddAlarm = (Button) findViewById(R.id.btnAddAlarm);
lvListAlarm = (ListView) findViewById(R.id.lvListAlarm);
adapter = new ArrayAdapter<AlarmData>(getContext(),
android.R.layout.simple_list_item_1);
lvListAlarm.setAdapter(adapter);
readSaveAlarmList();
// adapter.add(new AlarmData(System.currentTimeMillis()));
btnAddAlarm.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
addAlarm();
}
});
// 长按某项删除
lvListAlarm.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int position, long arg3) {
new AlertDialog.Builder(getContext())
.setTitle("操作选项")
.setItems(new CharSequence[] { "删除", "删除1" },
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 = adapter.getItem(position);
adapter.remove(ad);
saveAlarmList();
alarmManager.cancel(PendingIntent.getBroadcast(getContext(),
ad.getId(), new Intent(getContext(), AlarmReceiver.class), 0));
}
private void addAlarm() {
Calendar c = Calendar.getInstance();
new TPDiolog(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 (currentTime.getTimeInMillis() >= calendar.getTimeInMillis()) {
calendar.setTimeInMillis(calendar.getTimeInMillis() + 24
* 60 * 60 * 1000);
}
AlarmData ad = new AlarmData(calendar.getTimeInMillis());
adapter.add(ad);
alarmManager.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();
}
private static final String KEY_ALARM_LIST = "alarmlist";
private void saveAlarmList() {
Editor editor = getContext().getSharedPreferences(
AlarmView.class.getName(), Context.MODE_PRIVATE).edit();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < adapter.getCount(); i++) {
sb.append(adapter.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 readSaveAlarmList() {
SharedPreferences sp = getContext().getSharedPreferences(
AlarmView.class.getName(), Context.MODE_PRIVATE);
String content = sp.getString(KEY_ALARM_LIST, null);
if (content != null) {
String[] timeStrings = content.split(",");
for (String string : timeStrings) {
adapter.add(new AlarmData(Long.parseLong(string)));
}
}
}
// 自定义数据类型
private static class AlarmData {
private long time = 0;
private Calendar date;
private String timeLabel = "";
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 long getTime() {
return time;
}
public String getTimeLabel() {
return timeLabel;
}
public int getId() {
return (int) (getTime() / 1000 / 60);
}
@Override
public String toString() {
return getTimeLabel();
}
}
}
三、计时器
计时器的主要功能就是你先设定一个时间,然后点击开始,时间就会一秒一秒的减少,在这里我么主要用到了Timer这个系统的计时器,这代码中没有上面难懂的地方,有些地方已经给上注释了,所以直接贴代码,可能有些人会不知道Timer怎么用,之后的知识点中都会有提到。
package com.example.clock;
import java.util.Timer;
import java.util.TimerTask;
import android.R.integer;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Handler;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
public class TimerView extends LinearLayout {
public TimerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TimerView(Context context) {
super(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
btnStart = (Button) findViewById(R.id.btnStart);
btnPause = (Button) findViewById(R.id.btnPause);
btnResume = (Button) findViewById(R.id.btnResume);
btnReset = (Button) findViewById(R.id.btnReset);
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnStart.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
btnReset.setVisibility(View.VISIBLE);
}
});
btnPause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.VISIBLE);
}
});
btnResume.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnPause.setVisibility(View.VISIBLE);
btnResume.setVisibility(View.GONE);
}
});
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
etHour.setText("00");
etMin.setText("00");
etSec.setText("00");
btnReset.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
}
});
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) {
/*
* 这个方法是在Text改变过程中触发调用的, 它的意思就是说在原有的文本s中,
* 从start开始的count个字符替换长度为before的旧文本,
* 注意这里没有将要之类的字眼,也就是说一句执行了替换动作。
*/
if (!TextUtils.isEmpty(s)) {
int value = Integer.parseInt(s.toString());
if (value > 59) {
etHour.setText("59");
} else if (value < 0) {
etHour.setText("00");
}
}
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("00");
}
}
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("00");
}
}
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 (timerTask == null) {
allTimeCount = Integer.parseInt(etHour.getText().toString()) * 60
* 60 + Integer.parseInt(etMin.getText().toString()) * 60
+ Integer.parseInt(etSec.getText().toString());
timerTask = new TimerTask() {
@Override
public void run() {
allTimeCount--;
handle.sendEmptyMessage(MSG_WHAT_TIME_TICK);
if (allTimeCount <= 0) {
handle.sendEmptyMessage(MSG_WHAT_TIME_IS_UP);
stopTimer();
}
}
};
timer.schedule(timerTask, 1000, 1000);
}
}
private void stopTimer(){
if (timerTask!=null) {
timerTask.cancel();
timerTask=null;
}
}
private Handler handle = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_WHAT_TIME_TICK:
int hour = allTimeCount/60/60;
int min = (allTimeCount/60)%60;
int sec = allTimeCount%60;
etHour.setText(hour+"");
etMin.setText(min+"");
etSec.setText(sec+"");
break;
case MSG_WHAT_TIME_IS_UP:
new AlertDialog.Builder(getContext())
.setTitle("Time is up!")
.setMessage("Time is up!")
.setNegativeButton("Cancle", null).show();
btnReset.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
break;
default:
break;
}
};
};
private static final int MSG_WHAT_TIME_IS_UP = 1;
private static final int MSG_WHAT_TIME_TICK = 2;
private int allTimeCount = 0;
private Timer timer = new Timer();
private TimerTask timerTask = null;
private Button btnStart, btnPause, btnResume, btnReset;
private EditText etHour, etMin, etSec;
}
四、秒表
最后的秒表相信大家都不陌生,用到的知识正好之前的三个都有讲到,只要明白前三个后,这个就不难理解了。
package com.example.clock;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class StopWatchView extends LinearLayout {
private TextView tvHour,tvMin,tvSec,tvMsec;
private Button btnStart,btnPause,btnResume,btnReset,btnLap;
private ListView lvTimeList;
private ArrayAdapter<String> adapter;
public StopWatchView(Context context, 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");
btnStart = (Button) findViewById(R.id.btnSWStart);
btnPause = (Button) findViewById(R.id.btnSWPause);
btnResume = (Button) findViewById(R.id.btnSWResume);
btnLap = (Button) findViewById(R.id.btnSWLap);
btnReset = (Button) findViewById(R.id.btnSWReset);
btnStart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnStart.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
btnLap.setVisibility(View.VISIBLE);
}
});
btnPause.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.VISIBLE);
btnLap.setVisibility(View.GONE);
btnReset.setVisibility(View.VISIBLE);
}
});
btnResume.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startTimer();
btnResume.setVisibility(View.GONE);
btnPause.setVisibility(View.VISIBLE);
btnLap.setVisibility(View.VISIBLE);
btnReset.setVisibility(View.GONE);
}
});
btnReset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopTimer();
tenMSecs = 0;
adapter.clear();
btnReset.setVisibility(View.GONE);
btnLap.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnStart.setVisibility(View.VISIBLE);
}
});
btnLap.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
adapter.insert(String.format("%d:%d:%d.%d", tenMSecs/100/60/60,tenMSecs/100/60%60,tenMSecs/100%60,tenMSecs%100), 0);
}
});
btnLap.setVisibility(View.GONE);
btnPause.setVisibility(View.GONE);
btnResume.setVisibility(View.GONE);
btnReset.setVisibility(View.GONE);
lvTimeList = (ListView) findViewById(R.id.lvWatchTime);
adapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_list_item_1);
lvTimeList.setAdapter(adapter);
showTimerTask = new TimerTask() {
@Override
public void run() {
handle.sendEmptyMessage(MSG_WHAT_SHOW_TIME);
}
};
timer.schedule(showTimerTask, 200, 200);
}
private void startTimer(){
if (timerTask == null) {
timerTask = new TimerTask() {
@Override
public void run() {
tenMSecs++;
}
};
timer.schedule(timerTask, 10, 10);
}
}
private void stopTimer(){
if (timerTask != null) {
timerTask.cancel();
timerTask = null;
}
}
private int tenMSecs = 0;
private Timer timer =new Timer();
private TimerTask timerTask = null;
private TimerTask showTimerTask = null;
private static final int MSG_WHAT_SHOW_TIME = 1;
private Handler handle = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_WHAT_SHOW_TIME:
tvHour.setText(tenMSecs/100/60/60+"");
tvMin.setText(tenMSecs/100/60%60+"");
tvSec.setText(tenMSecs/100%60+"");
tvMsec.setText(tenMSecs%100+"");
break;
default:
break;
}
};
};
public void onDestroy() {
timer.cancel();
}
}
到此为止,自己的第一个实战算是完成了,但是就是界面很low,这个只是把基本的功能实现了,但是在界面上没有做很大的完善,在之后的实战中会慢慢改进的。
以上是关于Android实战第一篇——时钟+闹钟+计时器+秒表的主要内容,如果未能解决你的问题,请参考以下文章
深入理解定时器系列第三篇——定时器应用(时钟倒计时秒表和闹钟)