小的计时器程序(多线程+生命周期)

预备知识

  1. 默认情况下,同一应用的所有组件均在相同进程和线程(主线程)中运行
  2. 应用与android界面工具包组件几乎都在主线程中进行交互,因此有时也称为界面线程、UI线程。 不要阻塞UI线程
  3. 不要在UI线程外访问Android UI工具包
  4. 通过创建Thread类的子类来构造线程。Java定义了一个直接从根类Object中派生的Thread类。所有从这个类派生的子类或间接子类,均为线程。
  5. Android中创建的其他线程称为工作线程或后台线程
  6. 创建和执行一个线程需完成下列步骤
    1. 创建一个Thread类的子类
    2. 在Thread子类中重新定义自己的run()方法,在这个run()方法中包含了线程要实现的操作(通过Handler对象发送Message消息)
    3. 用关键字new 创建一个线程对象
    4. 调用线程对象的start()方法启动线程
    5. 线程启动后当执行run()方法完毕时,会自然进入终止状态
  7. Android中的线程抛弃了Java线程中一些不安全的做法。例如,在Java中终止一个Thread线程,可以调用stop()、destroy()等方法来实现,但在Android中,这些方法都没有实现,故不能直接使用。
  8. 在Android的多线程中,把需要传递的数据称为消息。
  9. Message是一个描述消息的数据结构类,Message包含了很多成员变量和方法。
    如下:在这里插入图片描述
  10. Android.os.Handler是Android中多个线程间消息传递和定时执行任务的“工具”类。Handler是消息的处理者,负责在多个线程之间发送Message和处理Message。
  11. Handler类在多线程中有两方面的应用:
    1. 发送消息,在不同的线程间传递数据,使用的方法为sendXXX();
    2. 定时执行任务,在指定的未来某时间执行某任务,使用的方法为postXXX()。
  12. 一个线程只能有一个Handler对象,通过该对象向所在线程发送消息。
  13. Handler类方法:
    在这里插入图片描述

1 设计好页面布局

一个“启动线程”按钮:用于启动计时器线程
一个“停止线程”按钮:用于停止计时器线程按钮
一个用于显示计时结果的TextView控件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintTop_toTopOf="parent">

        <Button
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginRight="5dp"
            android:layout_marginLeft="5dp"
            android:text="启动线程" />

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_marginRight="5dp"
            android:layout_marginLeft="5dp"
            android:text="停止线程" />
    </LinearLayout>

    <TextView
        android:id="@+id/viewOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="number"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout" />

</androidx.constraintlayout.widget.ConstraintLayout>

2 在MainActivity.java的类内设置私有全局变量

	private int count = 0;  // 保存计时的值
    private boolean Stop = true; // 计时状态,如果为停止状态则Stop值为true
    public TextView view1;  // 获取显示计时值的TextView控件
    private Button btn1;  // 获取启动计时线程的Button控件
    private Button btn2;  // 获取停止计时线程的Button控件
    private Handler handler = new Handler();  // 在此处MainActivity.java文件中,handler的作用是定时执行计时任务

3 实现Thread子类testThread,并通过handler进行周期性调用

实现Thread子类testThread

private class testThread extends Thread {
        public void run() {
            if(!Stop){count++;}  // 更新计时的值
            view1.setText(String.format(Locale.getDefault(),"%d",count));  // 更新textView内容
            handler.postDelayed(this,1000);  // 实现每隔1秒钟执行一次当前任务
        }
}

在MainActivity.java的类的onCreate函数里,通过handler创建计时器线程

handler.post(new testThread());

4 实现两个按钮的点击事件

创建onStart和onEnd两个私有接口

	private class onStart implements View.OnClickListener {
        public void onClick(View view) {
            Stop=false;
        }
    }

    private class onEnd implements View.OnClickListener {
        public void onClick(View view) {
            Stop=true;
        }
    }

在MainActivity.java的类的onCreate函数里,分别传入onStart和onEnd

btn1.setOnClickListener(new onStart());
btn2.setOnClickListener(new onEnd());

5 自定义onDestroy()函数

	protected void onDestroy(){
        super.onDestroy();
        Log.d("life circle","onDestroy; count: "+count+" stop: "+Stop);
    }

6 调用onDestroy之前调用onSaveInstanceState(),保存当前状态到Bundle savedInstanceState中,在onCreate中取出保存状态。

调用onDestroy之前调用onSaveInstanceState(),保存当前状态(count和Stop)到Bundle savedInstanceState中

	@Override
    public void onSaveInstanceState(Bundle savedInstanceState){
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("count",count);
        savedInstanceState.putBoolean("stop",Stop);
    }

在MainActivity.java的类的onCreate函数里,取出被保存的状态

		if(savedInstanceState!=null){
            count = savedInstanceState.getInt("count");
            Stop = savedInstanceState.getBoolean("stop");
        }

7 实现按返回键不销毁当前Activity

	// 下面该函数实现:Android 按返回键不销毁当前Activity
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event){
        if(keyCode == KeyEvent.KEYCODE_BACK){
            // 在activity中调用 moveTaskToBack (boolean nonRoot)方法即可将activity 退到后台,注意不是finish()退出。
            // 参数为false——代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
            // 参数为true——则忽略这个限制,任何activity都可以有效。
            Stop = true;
            moveTaskToBack(true);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

8 完整的MainActivity.java代码

包名这里不显示,不同项目包名不同

package XXX;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.util.Locale;

public class MainActivity extends AppCompatActivity {

    private int count = 0;  // 保存计时的值
    private boolean Stop = true; // 计时状态,如果为停止状态则Stop值为true
    public TextView view1;  // 获取显示计时值的TextView控件
    private Button btn1;  // 获取启动计时线程的Button控件
    private Button btn2;  // 获取停止计时线程的Button控件
    private Handler handler = new Handler();  // 在此处MainActivity.java文件中,handler的作用是定时执行计时任务
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view1 = findViewById(R.id.viewOne);
        btn1 = findViewById(R.id.button);
        btn2 = findViewById(R.id.button2);
        btn1.setOnClickListener(new onStart());
        btn2.setOnClickListener(new onEnd());
        if(savedInstanceState!=null){
            count = savedInstanceState.getInt("count");
            Stop = savedInstanceState.getBoolean("stop");
        }
        Log.d("life circle","onCreate;count: "+count+" stop: "+Stop);
        handler.post(new testThread());
    }
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState){
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("count",count);
        savedInstanceState.putBoolean("stop",Stop);
    }
    // 下面该函数实现:Android 按返回键不销毁当前Activity
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event){
        if(keyCode == KeyEvent.KEYCODE_BACK){
            // 在activity中调用 moveTaskToBack (boolean nonRoot)方法即可将activity 退到后台,注意不是finish()退出。
            // 参数为false——代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
            // 参数为true——则忽略这个限制,任何activity都可以有效。
            Stop = true;
            moveTaskToBack(true);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    protected void onDestroy(){
        super.onDestroy();
        Log.d("life circle","onDestroy; count: "+count+" stop: "+Stop);
    }
    private class onStart implements View.OnClickListener {
        public void onClick(View view) {
            Stop=false;
        }
    }

    private class onEnd implements View.OnClickListener {
        public void onClick(View view) {
            Stop=true;
        }
    }

    private class testThread extends Thread {
        public void run() {
            if(!Stop){count++;}
            view1.setText(String.format(Locale.getDefault(),"%d",count));
            handler.postDelayed(this,1000);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值