一个处理程序上有多个 Runnable,错误的重复行为
Multiple Runnables on one handler, wrong repeat behaviour
在我的 android 应用程序中,我需要在不同的时间间隔更新 UI 的不同部分(实际上是 ViewPager
内的 Fragment
。要做到这一点我创建了一个 Handler
和 3 个 Runnables
。使用 postDelayed(Runnable, delay)
方法,Runnables 应该在预定的时间间隔内重复自己。
目前我有 1 个 runnable,它必须每 100 毫秒更新一个 TextView
,另一个每 1000 毫秒更新一个 ProgressBar
,另一个每 2000 毫秒检查一些东西。
我看到计数器和进度条递增得太快,所以我放了一些代码来检查每次调用 Run()
方法之间的延迟,我发现第一个可运行对象每次都执行58 毫秒和进度条的一个 运行 每 508 毫秒。
然后我尝试只在 Handler(计数器)上留下第一个 Runnable,并且每 ~101 毫秒调用一次 Run()
方法。所以我假设其他 Runnable 可能会干扰 Message Queue 计划。然后我为每个 Runnable 创建了一个 Handler,但这样问题仍然存在,第一个 Runnable 持续 56~58 ms,第二个 Runnable 持续 508~510 ms。
关于为什么会发生这种行为有什么建议吗?
这是我的部分代码:
private static final int TIME_STEP_COUNTER = 100;
private static final int TIME_STEP_PROGRESS = 1000;
private static final int TIME_STEP_DIRECTOR = 2000;
private Handler counterHandler, progressHandler, directorHandler;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
// some code here
directorThread = new DirectorThread(wwp,TIME_STEP_DIRECTOR);
if(directorHandler == null){
directorHandler = new Handler();
directorHandler.post(directorThread);
}
startCounting();
}
StartCounting() 方法
public void startCounting(){
stdCounterUpdater = new CounterUpdaterThread(textViewCounter,TIME_STEP_COUNTER, increment100ms);
progressUpdaterThread = new ProgressUpdaterThread(progressBar,TIME_STEP_PROGRESS,textViewPercentage);
fixerThread = new FixerThread(wwp,TIME_STEP_FIXER);
if(counterHandler == null){
counterHandler = new Handler();
}
counterHandler.post(stdCounterUpdater);
if(progressHandler == null){
progressHandler = new Handler();
}
progressHandler.postDelayed(progressBarInitThread, DELAY_INIT_PROGRESS);
progressHandler.postDelayed(progressUpdaterThread, DELAY_INIT_PROGRESS + INIT_PROGRESS_DURATION);
counterLayout.setVisibility(View.VISIBLE);
}
线程
CounterUpdater
class CounterUpdaterThread implements Runnable{
public CounterUpdaterThread(TextView counterView, long deltaTime, float increment){
//Constructor with fields initialization
}
@Override
public void run(){
counter += increment;
changeCounterText();
if(counterHandler != null){
counterHandler.postDelayed(stdCounterUpdater,deltaTime);
}
}
}
ProgressUpdater
class ProgressUpdaterThread implements Runnable{
public ProgressUpdaterThread(ProgressBar pBar, long deltaTime, TextView percTW){
//Fields init
}
@Override
public void run(){
anim = new ProgressBarAnimation(progressBar, progress, progress + smoothScale);
progress += smoothScale;
anim.setDuration(PROGRESS_UPDATE_DURATION);
progressBar.startAnimation(anim);
percTW.setText(String.format(Locale.US,"%.1f", progressBar.getProgress()*100f/progressBar.getMax()) + "%");
if(progressHandler != null){
progressHandler.postDelayed(progressUpdaterThread,deltaTime);
}
}
}
DirectorThread
class DirectorThread implements Runnable{
public DirectorThread(WeeklyWorkPeriod wwp, long deltaTime){
//init
}
@Override
public void run(){
if(isStarted){
//....code.....
stopCounting();
isStarted = false;
//....code.....
}
}
else{
// ...code...
raiseMethod.requestProgressData(ProgressBarFragment.this,fragmentID);
startCounting();
isStarted = true;
}
}
if(directorHandler != null){
directorHandler.postDelayed(directorThread,deltaTime);
}
}
}
我也检查了这些文章和其他一些问题,但没有结果
我刚发现问题:与单个处理程序无关,而是与在 DirectorThread 中启动新回调有关。只需在 onCreateView()
方法中设置 isStarted
到 true
即可解决问题。
除此之外,我已按照 pskink 的建议将 postDelayed()
替换为 postAtTime()
,因为它恰好更准确。
在我的 android 应用程序中,我需要在不同的时间间隔更新 UI 的不同部分(实际上是 ViewPager
内的 Fragment
。要做到这一点我创建了一个 Handler
和 3 个 Runnables
。使用 postDelayed(Runnable, delay)
方法,Runnables 应该在预定的时间间隔内重复自己。
目前我有 1 个 runnable,它必须每 100 毫秒更新一个 TextView
,另一个每 1000 毫秒更新一个 ProgressBar
,另一个每 2000 毫秒检查一些东西。
我看到计数器和进度条递增得太快,所以我放了一些代码来检查每次调用 Run()
方法之间的延迟,我发现第一个可运行对象每次都执行58 毫秒和进度条的一个 运行 每 508 毫秒。
然后我尝试只在 Handler(计数器)上留下第一个 Runnable,并且每 ~101 毫秒调用一次 Run()
方法。所以我假设其他 Runnable 可能会干扰 Message Queue 计划。然后我为每个 Runnable 创建了一个 Handler,但这样问题仍然存在,第一个 Runnable 持续 56~58 ms,第二个 Runnable 持续 508~510 ms。
关于为什么会发生这种行为有什么建议吗?
这是我的部分代码:
private static final int TIME_STEP_COUNTER = 100;
private static final int TIME_STEP_PROGRESS = 1000;
private static final int TIME_STEP_DIRECTOR = 2000;
private Handler counterHandler, progressHandler, directorHandler;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
// some code here
directorThread = new DirectorThread(wwp,TIME_STEP_DIRECTOR);
if(directorHandler == null){
directorHandler = new Handler();
directorHandler.post(directorThread);
}
startCounting();
}
StartCounting() 方法
public void startCounting(){
stdCounterUpdater = new CounterUpdaterThread(textViewCounter,TIME_STEP_COUNTER, increment100ms);
progressUpdaterThread = new ProgressUpdaterThread(progressBar,TIME_STEP_PROGRESS,textViewPercentage);
fixerThread = new FixerThread(wwp,TIME_STEP_FIXER);
if(counterHandler == null){
counterHandler = new Handler();
}
counterHandler.post(stdCounterUpdater);
if(progressHandler == null){
progressHandler = new Handler();
}
progressHandler.postDelayed(progressBarInitThread, DELAY_INIT_PROGRESS);
progressHandler.postDelayed(progressUpdaterThread, DELAY_INIT_PROGRESS + INIT_PROGRESS_DURATION);
counterLayout.setVisibility(View.VISIBLE);
}
线程
CounterUpdater
class CounterUpdaterThread implements Runnable{
public CounterUpdaterThread(TextView counterView, long deltaTime, float increment){
//Constructor with fields initialization
}
@Override
public void run(){
counter += increment;
changeCounterText();
if(counterHandler != null){
counterHandler.postDelayed(stdCounterUpdater,deltaTime);
}
}
}
ProgressUpdater
class ProgressUpdaterThread implements Runnable{
public ProgressUpdaterThread(ProgressBar pBar, long deltaTime, TextView percTW){
//Fields init
}
@Override
public void run(){
anim = new ProgressBarAnimation(progressBar, progress, progress + smoothScale);
progress += smoothScale;
anim.setDuration(PROGRESS_UPDATE_DURATION);
progressBar.startAnimation(anim);
percTW.setText(String.format(Locale.US,"%.1f", progressBar.getProgress()*100f/progressBar.getMax()) + "%");
if(progressHandler != null){
progressHandler.postDelayed(progressUpdaterThread,deltaTime);
}
}
}
DirectorThread
class DirectorThread implements Runnable{
public DirectorThread(WeeklyWorkPeriod wwp, long deltaTime){
//init
}
@Override
public void run(){
if(isStarted){
//....code.....
stopCounting();
isStarted = false;
//....code.....
}
}
else{
// ...code...
raiseMethod.requestProgressData(ProgressBarFragment.this,fragmentID);
startCounting();
isStarted = true;
}
}
if(directorHandler != null){
directorHandler.postDelayed(directorThread,deltaTime);
}
}
}
我也检查了这些文章和其他一些问题,但没有结果
我刚发现问题:与单个处理程序无关,而是与在 DirectorThread 中启动新回调有关。只需在 onCreateView()
方法中设置 isStarted
到 true
即可解决问题。
除此之外,我已按照 pskink 的建议将 postDelayed()
替换为 postAtTime()
,因为它恰好更准确。