天天看點

【Android實驗】線程的使用-計時器

目錄

  • 實驗目的
  • 實驗要求
  • 實驗過程
    • 實驗結果
    • 實驗代碼
      • 界面部分
      • 核心代碼
      • 設計思路
  • 實驗總結

熟悉和掌握Android線程的使用

  1. 完成一個秒表,具備啟停功能,正确使用工作線程完成界面重新整理
  2. 分析秒表的計時是否準确,原因是什麼,如何保證秒表計時準确?

【Android實驗】線程的使用-計時器

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="秒表"
        android:textAlignment="center"
        android:textSize="40dp"
        />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="00:00:00"
            android:id="@+id/tv_time"
            android:textAlignment="center"
            android:textSize="60dp"/>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
                <Space
                    android:layout_width="120dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    />

            <Button
                android:id="@+id/btn_clear"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="清零"
                android:textColor="#000000"
                android:textSize="25dp"
                android:background="#99FFFF"/>

            <Button
                android:id="@+id/btn_start"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="計時"
                 android:layout_weight="1"
                 android:textSize="25dp"
                android:background="#FFC8B4"
                />
            <Button
                 android:id="@+id/btn_stop"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="停止"
                 android:layout_weight="1"
                 android:textSize="25dp"
                android:background="#CCFF99"
                />
        </LinearLayout>
</LinearLayout>
           

Timer.java

package com.example.administrator.exp5;

import android.app.Activity;
import android.content.Intent;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class Timer extends AppCompatActivity {
    private static Handler handler = new Handler();
    private static TextView tv_time = null;
    private static Button btn_clear,btn_start,btn_stop;

    private static String time;

    private int min=0,sec=0,psec= 0;

    boolean runflag = true;
    int status = 0; // 0 - clear ; 1 - start ; 2 - stop
    long last,templast = -1;

    String str="";

    private Thread workThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tv_time = (TextView)findViewById(R.id.tv_time);
        btn_clear = (Button)findViewById(R.id.btn_clear);
        btn_start = (Button)findViewById(R.id.btn_start);
        btn_stop = (Button)findViewById(R.id.btn_stop);

        workThread = new Thread(null,RefreshLabel,"workThread");
        workThread.start();
        last = System.currentTimeMillis();

        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //計時開始
                status = 1;
                if(templast != -1)
                {
                    last = templast;
                }
            }
        });
        btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //停止計時
                status = 2;
                templast = last;
            }
        });
        btn_clear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                min = sec = psec = 0;
                //清零
                status = 0;
                last = System.currentTimeMillis();
                tv_time.setText("00:00:00");
                templast = -1;
            }
        });
    }

    private Runnable RefreshLabel = new Runnable() {
        @Override
        public void run() {
            try{
                while(runflag)
                {
                    Thread.sleep(50);
                    if(status == 1)
                    {
                        int t=0;
                        long tmp = System.currentTimeMillis();
                        long cha = tmp - last;

                        t = (int)cha/1000;
                        psec = (int)cha - t * 1000;
                        psec %= 100;
                        sec = t - ((int)t/60)*60;
                        min = (int)t/60;
                        if(min == 60)
                        {
                            min = 0;
                        }
                        str = "";
                        str = str + String.format("%02d",min) + ":" +String.format("%02d",sec) + ":" + String.format("%02d",psec);

                        tv_time.post(new Runnable() {
                            @Override
                            public void run() {
                                tv_time.setText(str);
                            }
                        });
                    }
                }
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    };
}
           

    秒表需要完成停啟功能,也就是說需要能夠停下來,而且在停下來以後需要能夠繼續計時。這個計時的工作需要傳遞給一個子程序來做,每隔一段時間就重新整理一次界面,進而達到計時的效果。

    如何使秒表計時更加準确?可以通過sleep(1000)來計時,或者采取不斷通路系統時間的方式來計時。兩種方式相比較,第二種方式更加準确,第一種解決方案由于sleep時間是人為設定的,跟手機的性能有一定關系,除此之外,由于程式間斷性執行,這些時間也會計算到總時間中,是以第一種方案計時不準确。應該采用第二種計時方式。

    本實驗主要是練習線程的使用,線程需要實作\(Runnable\)借口,并重載\(run()\)函數,在該函數中寫入秒表運作的代碼,進行計算:

private Runnable RefreshLabel = new Runnable(){
    @Override
    public void run(){
        try{
            
        }
        catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}
           

然後建立Thread對象,将Runnable對象作為參數傳遞給Thread對象。

private Thread workThread;
workThread = new Thread(null,RefreshLabel,"workThread")
           

需要的三個參數,第一個參數表示線程組,第二個參數是需要執行的Runnable對象,第三個參數是參數名稱。

關于時間計算:

通過

System.currentTimeMillis()

函數傳回目前計算機的時間所對應的毫秒數。

時間換算如下:

1min = 60s

1s = 1000ms

時間計算部分代碼:

long tmp = System.currentTimeMillis();
long cha = tmp - last;
t = (int)cha/1000;
psec = (int)cha - t * 1000;
psec %= 100;
sec = t - ((int)t/60)*60;
min = (int)t/60;
if(min == 60)
{
	min = 0;
}
str = "";
str = str + String.format("%02d",min) + ":" +String.format("%02d",sec) + ":" + String.format("%02d",psec);
           

另外,由于單線程中,不能再UI線程外通路Android UI 工具包,則調用\(View.post()\)方法,進行異步通信。實作界面的動态更新。

代碼改變世界