Android通过子线程和handler实现倒计时,可以开始暂停倒计时
布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:orientation="vertical"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始和暂停倒计时"
android:onClick="btnDaoJiShi"/>
<TextView android:text="10秒\n倒计时" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="90sp"
android:id="@+id/textView"/>
</LinearLayout>
代码如下:
package tech.androidstudio.handlerdemotimer;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements Runnable {
private Handler mainHandler;
private TextView mTextView;
private Thread mThread;
private boolean mflag;
private int mCount=10;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//主线程的 handler 接收到 子线程的消息,然后修改TextView的显示
mainHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int what = msg.what;
switch (what){
case 1:
int arg1 = msg.arg1;
Log.d("Kodulf","Handler arg1="+arg1);
Log.d("Kodulf", "TestView =" + mTextView.getText().toString());
mTextView.setText(String.valueOf(arg1));
break;
}
}
};
mTextView=(TextView)findViewById(R.id.textView);
//子线程的初始化
mThread = new Thread(this);
}
//TODO 这里才是最关键的部分:首先判断子线程是否是活动的状态,
//TODO 如果不是活动的话,就是开始计时器或者重启计时器
//TODO 如果是活动的话,就是暂停计时器。
public void btnDaoJiShi(View view) {
Log.d("Kodulf","mThread state"+mThread.getState());
Log.d("Kodulf","mThread toString"+mThread.toString());
if(!mThread.isAlive()){
//开始计时器或者是重启计时器,设置标记为true
mflag=true;
//判断是否是第一次启动,如果是不是第一次启动,那么状态就是Thread.State.TERMINATED
//不是的话,就需要重新的初始化,因为之前的已经结束了。
//并且要判断这个mCount 是否为-1,如果是的话,说名上一次的计时已经完成了,那么要重新设置。
if(mThread.getState()==Thread.State.TERMINATED){
mThread = new Thread(this);
if(mCount==-1) mCount=10;
mThread.start();
}else{
mThread.start();
}
}else {
//暂停计时器,设置标记为false
mflag=false;
//不可以使用 stop 方法,会报错,java.lang.UnsupportedOperationException
//mThread.stop();
}
}
@Override
public void run() {
//子线程必须要设置这个标记mflag和倒计时数。
while(mflag&&mCount>=0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//每间隔 一秒钟 发送 一个Message 给主线程的 handler让主线程的hanlder 来修改UI
//注意 这里的 message可以是通过obtain来获取 这样节省内存,它会自动的看有没有可以复用的,就不重复创建了
Message message = Message.obtain();
message.what=1;
message.arg1=mCount;
mainHandler.sendMessage(message);
Log.d("Kodulf","mCount="+mCount--);
}
}
//一定记住了要在onDestroy方法里面停止线程,这里数字小看不出来,如果在其他的地方可能就会影响性能了
@Override
protected void onDestroy() {
super.onDestroy();
mflag=false;
}
}