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; } }