Android学习笔记------简单倒计时程序,设置时间,开始计时,结束计时,再次开始计时
今天学习了Handler这个类。
Handler这个类在Android程序中,用于主线程与子线程之间的通信,利用多线程目的在于处理一些耗时操作。
先看一下效果图
中间显示倒计时的是一个TextView,
然后是一个编辑框EditView,用于输入倒计时时间,最后是两个按钮Button
整个布局文件 activity_main 如下:
<?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"
android:padding="10dp">
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.2"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintVertical_bias="0.3"
android:textSize="70sp"
android:textStyle="bold"
android:text="0"
android:background="@drawable/bg_edit"
android:gravity="center"/>
<EditText
android:id="@+id/editView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.7"
android:background="@drawable/bg_edit"
android:inputType="number"
android:hint="请输入定时时间(s):"
android:paddingLeft="20dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintVertical_bias="0.85"
android:background="@drawable/bg_edit">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@color/colorAccent"
android:padding="10dp"
android:text="开始倒计时"
android:textSize="25sp" />
<View
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_width="1dp"
android:background="#000"
android:layout_height="match_parent"/>
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:background="@color/colorAccent"
android:text="结束倒计时"
android:textSize="25sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
drawable/bg_edit 代码如下,简单设置了一下描边
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="#000" android:width="1dp"/>
<corners android:radius="10dp"/>
<padding android:bottom="5dp" android:top="5dp" android:left="5dp" android:right="5dp"/>
</shape>
使用约束布局,实现了一个简单的界面(约束布局还在学习中,所以写的不是很好 (/▽\) )
然后就是实现功能了。
首先在MainActivity里面声明所需的属性
public class MainActivity extends AppCompatActivity {
private Handler mHandler;//消息收集处理
private EditText mEditText;//编辑框
private TextView mTextView;//显示框
private Button mStart ,mCancel;//两个按钮
private Thread mThread;//线程类对象引用
private int time;//倒计时时间
private boolean isCancel;//倒计时是否被取消
在MainActivity创建一个线程类继承自Thread
class MyThread extends Thread {
@Override
public void run() {
//子线程的具体操作
for (int i = time; i >= 0 ; i--) {
try {
//每隔一秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//向主线程发送信息
Message message = mHandler.obtainMessage();
//如果倒计时已经被取消
if (isCancel) {
isCancel = false;
i = 0;
message.what = 0;
} else
message.what = 1;
message.arg1 = i;
//发送
mHandler.sendMessage(message);
}
}
}
在 protected void onCreate(Bundle savedInstanceState) 中找到控件
mEditText = findViewById(R.id.editView);
mStart = findViewById(R.id.start);
mTextView = findViewById(R.id.textView);
mCancel = findViewById(R.id.cancel);
然后在 protected void onCreate(Bundle savedInstanceState)中创建Handler对象
//Handler----英文意思是搬运工;操作者;处理者,也就是对接收到的信息进行处理
//子线程通过Handler转递消息给主线程,然后主线程中Handler进行处理
mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//msg.what--消息类型
//按照消息类型进行处理
switch (msg.what) {
//具体处理操作
case 1 :
mTextView.setText("" + msg.arg1);
if (msg.arg1 == 0) {
Toast.makeText(MainActivity.this,"倒计时完成",Toast.LENGTH_SHORT).show();
}
break;
case 0 :
mTextView.setText("" + msg.arg1);
Toast.makeText(MainActivity.this,"倒计时已取消",Toast.LENGTH_SHORT).show();
break;
}
}
};
为两个按钮设置点击事件
//点击开始倒计时
mStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//启动子线程,mThread == null时启动,mThread.isAlive() == false时重新创建线程对象并启动
//线程run方法结束后,线程死亡( .isAlive() == false ),但线程对象仍然存在
//如果上一个倒计时已经结束,或者还没有启动过倒计时,则启动一个新的倒计时
if (mThread == null || !mThread.isAlive()) {
// if (mThread != null)
// Log.d("mThread.isAlive() ", String.valueOf(mThread.isAlive()));
//获取设置的时间
time = Integer.parseInt(mEditText.getText().toString());
mThread = new MyThread();
mThread.start();
}
}
});
//点击取消
mCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//isCancel为false,
isCancel = true;
}
});
子线程通过调用Handler的实例化对象的sendMessage(message);方法,将message加入到MessageQueue中,然后重写Handler的
public void handleMessage(@NonNull Message msg)方法,对MessageQueue中的message分别进行处理。
完整MainActivity代码在这里:点我传送
灵感及学习思路来自于这位大神的博客:大神博客
上一篇: MapReduce核心 - - - Shuffle
下一篇: Harris 角点检测