近几天做了个多功能时钟,分享一下
主界面
对应的代码:
MainActivity.java
package com.example.clock;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TabHost;
public class MainActivity extends Activity {
private TabHost tabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tabHost = (TabHost) findViewById(android.R.id.tabhost);
tabHost.setup();
// Call setup() before adding tabs if loading TabHost using
// findViewById().
// However: You do not need to call setup() after getTabHost() in
// TabActivity.
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));
}
}
TabTime.java
package com.example.clock;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;
//tabtime就显示系统时间,注释部分表示是否在当前页面,如果在就发送message,不在就不发送
//有没有其实无所谓
public class TabTime extends LinearLayout {
private TextView tvTime;
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
tvTime.setText(new SimpleDateFormat("HH:mm:ss", Locale.CHINA)
.format(new Date()));
//if (getVisibility() == View.VISIBLE) {
myHandler.sendEmptyMessage(0);
//}
}
};
public TabTime(Context context) {
super(context);
}
public TabTime(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TabTime(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
tvTime = (TextView) findViewById(R.id.tvTime);
myHandler.sendEmptyMessage(0);
}
// @Override
// protected void onVisibilityChanged(View changedView, int visibility) {
// super.onVisibilityChanged(changedView, visibility);
//
// if (visibility == View.VISIBLE) {
// myHandler.sendEmptyMessage(0);
// } else {
// myHandler.removeMessages(0);
// }
// }
}
package com.example.clock;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
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.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
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.TimePicker;
import com.example.clock.tool.AlarmReceiver;
import com.example.clock.tool.MyTimePickerDialog;
//闹钟功能
public class TabAlarm extends LinearLayout {
private Button btn_add;
private ListView listView;
// 自定义数据类型用于adapter
private class AlarmData {
private long time;
private Date date;
public AlarmData(long time) {
this.time = time;
date = new Date(time);
}
public long getTime() {
return time;
}
public String getTimeLabel() {
return new SimpleDateFormat("MM-dd HH:mm", Locale.CHINA)
.format(date);
}
@Override
public String toString() {
return getTimeLabel();
}
};
private ArrayAdapter<AlarmData> adapter;
private AlarmManager alarmManager;
public TabAlarm(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public TabAlarm(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TabAlarm(Context context) {
super(context);
init();
}
private void init() {
alarmManager = (AlarmManager) getContext().getSystemService(
Context.ALARM_SERVICE);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
btn_add = (Button) findViewById(R.id.btn_add);
listView = (ListView) findViewById(R.id.lvAlarmList);
adapter = new ArrayAdapter<TabAlarm.AlarmData>(getContext(),
android.R.layout.simple_list_item_1);
listView.setAdapter(adapter);
readAlarmList();
btn_add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addAlarm();
}
});
// btn用来增加闹钟,listview的长按事件用来删除闹钟
listView.setOnItemLongClickListener(new 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:
adapter.remove(adapter
.getItem(position));
saveAlarmList();
break;
}
}
}).setNegativeButton("取消", null).show();
return true;
}
});
}
private void addAlarm() {
Calendar calendar = Calendar.getInstance();
new MyTimePickerDialog(getContext(), new OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, hourOfDay);
c.set(Calendar.MINUTE, minute);
Calendar currentCalendar = Calendar.getInstance();
if (c.getTimeInMillis() <= currentCalendar.getTimeInMillis()) {
c.setTimeInMillis(currentCalendar.getTimeInMillis() + 24
* 60 * 60 * 1000);
}
adapter.add(new AlarmData(c.getTimeInMillis()));
saveAlarmList();
// 使用TimePickerDialog时,点击对话框的确定按钮,会添加两条数据,
// 原因是OnTimeSetListener中的onTimeSet()执行了两次,
// 点击确定按钮时执行一次,
// 对话框取消时,TimePickerDialog的onStop()方法中也执行了一次。
// 解决方法:重写TimePickerDialog类,并覆盖onStop()
// 在com.example.clock.tool包中
alarmManager.setExact(AlarmManager.RTC_WAKEUP, SystemClock
.elapsedRealtime(), PendingIntent.getBroadcast(
getContext(), 0, new Intent(getContext(),
AlarmReceiver.class), 0));
// setRepeating在API19以后不再准确,我试了好多种组合都不行
}
}, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE),
true).show();
}
private void saveAlarmList() {
Editor editor = getContext().getSharedPreferences(
TabAlarm.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(",");
}//每条记录用逗号隔开
String content = "";
if (!sb.toString().equals("")) {
content = sb.toString().substring(0, sb.length() - 1);
}
editor.putString("AlarmList", content);
Log.i("record", content);
editor.commit();
}
private void readAlarmList() {
SharedPreferences sp = getContext().getSharedPreferences(
TabAlarm.class.getName(), Context.MODE_PRIVATE);
String content = sp.getString("AlarmList", null);
if (!content.equals("")) {
String[] timeString = content.split(",");
for (String string : timeString) {
adapter.add(new AlarmData(Long.parseLong(string)));
}
}
}
}
里面还有一个BroadcastReceiver需要注册
package com.example.clock.tool;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "闹铃响了", Toast.LENGTH_SHORT).show();
}
}
以及重写的MyTimePickerDialog.java
package com.example.clock.tool;
import android.app.TimePickerDialog;
import android.content.Context;
public class MyTimePickerDialog extends TimePickerDialog {
public MyTimePickerDialog(Context context, OnTimeSetListener callBack,
int hourOfDay, int minute, boolean is24HourView) {
super(context, callBack, hourOfDay, minute, is24HourView);
}
public MyTimePickerDialog(Context context, int theme,
OnTimeSetListener callBack, int hourOfDay, int minute,
boolean is24HourView) {
super(context, theme, callBack, hourOfDay, minute, is24HourView);
}
@Override
protected void onStop() {
// 注释掉,防止onTimeSet()执行两次
// super.onStop();
}
}
package com.example.clock;
import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
//计时器功能
public class TabTimer extends LinearLayout {
private Spinner spinner;
private TextView tv;
private ArrayAdapter<CharSequence> adapter;
private long tempMillis, defaultMillis;
private Button btn1, btn2;
private MyCount mCount;
public TabTimer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TabTimer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TabTimer(Context context) {
super(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
tv = (TextView) findViewById(R.id.tvShowTime);
btn1 = (Button) findViewById(R.id.button1);
btn2 = (Button) findViewById(R.id.button2);
spinner = (Spinner) findViewById(R.id.spinner1);
adapter = ArrayAdapter.createFromResource(getContext(), R.array.time,
android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
final long[] arrayTime = {30*1000, 1*60*1000, 2*60*1000, 5*60*1000};
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
tempMillis = arrayTime[pos];
defaultMillis = tempMillis;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
tempMillis = arrayTime[0];// 默认30s
defaultMillis = tempMillis;
}
});
//spinner获取时间,后面两个button操作整个自定义计时器
//逻辑虽然简单,但比较复杂。我调试了好一会儿
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (btn1.getText().toString()
.equals(getResources().getString(R.string.start))) {
//点击开始按钮
mCount = new MyCount(tempMillis, 1000);
mCount.start();
btn2.setEnabled(true);
btn1.setText(getResources().getString(R.string.quit));
} else if (btn1.getText().toString()
.equals(getResources().getString(R.string.quit))) {
//点击取消按钮
mCount.cancel();
btn2.setEnabled(false);
btn1.setText(getResources().getString(R.string.start));
tv.setText("");
btn2.setText(getResources().getString(R.string.pause));
tempMillis = defaultMillis;
}
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (btn2.getText().toString()
.equals(getResources().getString(R.string.pause))) {
//点击暂停按钮
mCount.cancel();
btn2.setText(getResources().getString(R.string.continu));
} else if (btn2.getText().toString()
.equals(getResources().getString(R.string.continu))) {
//点击继续按钮
btn2.setText(getResources().getString(R.string.pause));
mCount = new MyCount(tempMillis, 1000);
mCount.start();
}
}
});
}
//自定义计时器。网上说cancel失效,但我试了一下可行
//用法比较简单,网上或者API上都有
class MyCount extends CountDownTimer {
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onFinish() {
tv.setText("计时结束!");
}
@Override
public void onTick(long millisUntilFinished) {
tv.setText("剩余" + millisUntilFinished / 1000 + "秒。。。");
tempMillis = millisUntilFinished;
}
}
}
package com.example.clock;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
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;
import com.example.clock.tool.MyDataFormat;
//秒表功能
//网上的方法大多只有精确到秒,显然精度不够
//而且都是用的sendMessageDelayed方法,可能会不准
//我用的是系统时间,然后加以转化
public class TabStopWatch extends LinearLayout {
private Button btn_start, btn_reset;
private TextView single, total;
private ListView timeCount;
private ArrayAdapter<String> adapter;
private long single_start, total_start;
private int count;// adapter中的显示条目的计数器
private boolean isReset, isPause;// 是否重置和暂停
public TabStopWatch(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TabStopWatch(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TabStopWatch(Context context) {
super(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
single = (TextView) findViewById(R.id.single);
total = (TextView) findViewById(R.id.total);
btn_start = (Button) findViewById(R.id.btn_start);
btn_reset = (Button) findViewById(R.id.btn_reset);
timeCount = (ListView) findViewById(R.id.timeCount);
adapter = new ArrayAdapter<String>(getContext(),
android.R.layout.simple_list_item_1);
timeCount.setAdapter(adapter);
single.setText("00:00.00");
total.setText("00:00.00");
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (btn_start.getText().toString()
.equals(getResources().getString(R.string.start))) {
// 点击开始按钮
isReset = false;
isPause = false;
count = 0;
btn_start.setText(getResources().getString(R.string.pause));
btn_reset.setEnabled(true);
// 如果是第一次启动,formatLong返回0,
// 如果是暂停后启动,返回的是系统时间减去textview显示的时间
single_start = System.currentTimeMillis()
- MyDataFormat.formatLong(single.getText()
.toString());
total_start = System.currentTimeMillis()
- MyDataFormat.formatLong(total.getText()
.toString());
// 获取时间
singleTextTime();
totalTextTime();
} else if (btn_start.getText().toString()
.equals(getResources().getString(R.string.pause))) {
// 点击停止按钮
isPause = true;
btn_start.setText(getResources().getString(R.string.start));
btn_reset.setText(getResources().getString(R.string.reset));
}
}
});
btn_reset.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (btn_reset.getText().toString()
.equals(getResources().getString(R.string.count))) {
// 点击计次按钮
adapter.add("计数:" + count++ + " "
+ single.getText().toString());
single.setText("00:00.00");
single_start = System.currentTimeMillis();
singleTextTime();
} else if (btn_reset.getText().toString()
.equals(getResources().getString(R.string.reset))) {
// 点击复位按钮
adapter.clear();
single.setText("00:00.00");
total.setText("00:00.00");
btn_reset.setEnabled(false);
isReset = true;
btn_reset.setText(getResources().getString(R.string.count));
}
}
});
}
private Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1) {
if (!isPause && !isReset) {
single.setText(MyDataFormat.format(
System.currentTimeMillis(), single_start));
myHandler.sendEmptyMessage(1);
}
} else if (msg.what == 2) {
if (!isPause && !isReset) {
total.setText(MyDataFormat.format(
System.currentTimeMillis(), total_start));
myHandler.sendEmptyMessage(2);
}
}
};
};
private void singleTextTime() {
myHandler.sendEmptyMessage(1);
}
private void totalTextTime() {
myHandler.sendEmptyMessage(2);
}
}
这里需要用到工具类
package com.example.clock.tool;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class MyDataFormat {
// 把时间差的"00:00:000"格式变为"00:00.00"
public static String format(long data, long ori) {
String temp = new SimpleDateFormat("mm:ss:SSS", Locale.CHINA)
.format(data - ori);
int position = temp.lastIndexOf(":");
return temp.substring(0, position) + "."
+ temp.substring(position + 1, temp.length() - 1);
}
// 把string的"00:00.00"格式变为long类型
public static long formatLong(String data){
int position = data.lastIndexOf(".");
data = data.substring(0, position) + ":"
+ data.substring(position + 1, data.length() - 1);
SimpleDateFormat sdf = new SimpleDateFormat("mm:ss:SSS", Locale.CHINA);
Date date = null;
try {
date = sdf.parse(data);
} catch (ParseException e) {
e.printStackTrace();
}
return date.getTime();
}
}
最后贴一些资源和布局文件吧:
main.xml
<LinearLayout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.clock.MainActivity" >
<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.TabTime 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:gravity="center" android:textAppearance="?android:attr/textAppearanceLarge" />
</com.example.clock.TabTime>
<com.example.clock.TabAlarm android:id="@+id/tabAlarm" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Button android:id="@+id/btn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:text="@string/addAlarm" />
<ListView android:id="@+id/lvAlarmList" android:layout_width="match_parent" android:layout_height="wrap_content" >
</ListView>
</com.example.clock.TabAlarm>
<com.example.clock.TabTimer android:id="@+id/tabTimer" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<Spinner android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" />
<TextView android:id="@+id/tvShowTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:enabled="false" android:gravity="center" android:textSize="30sp" />
<Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/start" />
<Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:enabled="false" android:text="@string/pause" />
</com.example.clock.TabTimer>
<com.example.clock.TabStopWatch android:id="@+id/tabStopWatch" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >
<TextView android:id="@+id/single" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:textSize="15sp" />
<TextView android:id="@+id/total" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:textSize="30sp" />
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" >
<Button android:id="@+id/btn_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/start" />
<Button android:id="@+id/btn_reset" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:enabled="false" android:text="@string/count" />
</LinearLayout>
<ListView android:id="@+id/timeCount" android:layout_width="match_parent" android:layout_height="wrap_content" >
</ListView>
</com.example.clock.TabStopWatch>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout>
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Clock</string>
<string name="addAlarm">添加闹钟</string>
<string name="start">开始</string>
<string name="pause">暂停</string>
<string name="quit">取消</string>
<string name="continu">继续</string>
<string name="count">计次</string>
<string name="reset">复位</string>
</resources>
arrays.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="time">
<item>30秒</item>
<item>1分钟</item>
<item>2分钟</item>
<item>5分钟</item>
</string-array>
</resources>