一个处理程序上有多个 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);
        }
    }
}

我也检查了这些文章和其他一些问题,但没有结果

Repeating Tasks

Handler Vs Timer

Handlers and Loopers

我刚发现问题:与单个处理程序无关,而是与在 DirectorThread 中启动新回调有关。只需在 onCreateView() 方法中设置 isStartedtrue 即可解决问题。

除此之外,我已按照 pskink 的建议将 postDelayed() 替换为 postAtTime(),因为它恰好更准确。