目前在项目中使用过的定时器主要是两种方式:1.handler的延时任务 2.timer的定时器
下面主要来介绍这两种方式 定时器的用法,和遇到的坑 :
1.handler的延时任务
写了一个demo,是关于hanlder发送延时消息和 取消延时消息的
image.png
package com.phicomm.android.test.demo;
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.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mOpenButton;
private Handler mHandler;
private Runnable mRunnable;
private Button mCloseButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mOpenButton = (Button) findViewById(R.id.btn_open);
mCloseButton = (Button) findViewById(R.id.btn_close);
mOpenButton.setOnClickListener(this);
mCloseButton.setOnClickListener(this);
mHandler = new Handler();
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_open:
mRunnable = new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "1s后延时任务执行了"+mRunnable.toString(), Toast.LENGTH_SHORT).show();
}
};
mHandler.postDelayed(mRunnable,1000);
break;
case R.id.btn_close:
mHandler.removeCallbacksAndMessages(mRunnable);
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(mRunnable);
}
}
}
但是在实际运用的过程中,常常会出现无法移除延时消息的问题,这个问题主要是因为两个runnable的对象不是同一个,
当Activity进入后台运行后再转入前台运行,removeCallbacks无法将updateThread从message queue中移除。这是为什么呢?
在Activity由前台转后台过程中,线程是一直在运行的,但是当Activity转入前台时会重新定义Runnable runnable;也就是说此时从message queue移除的runnable与原先加入message queue中的runnable并非是同一个对象。 解决方式1:如果把runnable定义为静态的则removeCallbacks不会失效,对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,我们做如下修改就能解决上面的这个问题.
解决方式2:将所有的runnable任务放到一个集合中,根据runnable的id移除相应的任务,即可以解决这个问题
2.timer的延时任务
同样用上面的demo来说明使用方法:
要注意的是:
TimerTask运行在一个单独的线程里,而不是UI线程。所以使用Android timer时,注意android的单线程原则,确保线程安全。不要在TimerTask的run方法中做UI相关的操作,如:TextView.setText()等,这样可能会导致UI线程阻塞。如果需要可以使用handler向UI线程发消息,具体处理由UI线程自己完成。在使用完Timer之后,要使用Timer的cancel方法取消Timer,否则Timer一直在运行。
package com.phicomm.android.test.timer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.phicomm.android.test.demo.R;
import java.util.Timer;
import java.util.TimerTask;
public class TimerActivity extends AppCompatActivity implements View.OnClickListener {
private Button mOpenButton;
private Button mCloseButton;
private Timer mTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
initView();
}
private void initView() {
mOpenButton = (Button) findViewById(R.id.btn_open);
mCloseButton = (Button) findViewById(R.id.btn_close);
mOpenButton.setOnClickListener(this);
mCloseButton.setOnClickListener(this);
mTimer = new Timer();
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_open:
TimerTask timerTask = new TimerTask(){
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(TimerActivity.this, "1s后延时任务执行了", Toast.LENGTH_SHORT).show();
}
});
}
};
mTimer.schedule(timerTask,1000);
break;
case R.id.btn_close:
mTimer.cancel();
break;
}
}
}
这里需要注意的是,timer的cancel方法只能执行一次,不能在调用了cancel之后再进行timer的任务执行。
网友评论