首頁 > 軟體

Android開發實戰鬧鐘專案

2022-09-12 18:02:05

本文範例為大家分享了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;
            }
        }
    };
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com