Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/219.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 精确的android线程处理程序postDelayed_Java_Android_Multithreading_Threadpool - Fatal编程技术网

Java 精确的android线程处理程序postDelayed

Java 精确的android线程处理程序postDelayed,java,android,multithreading,threadpool,Java,Android,Multithreading,Threadpool,我一直在尝试用Android编写节拍器,但是我发现使用Handler postdelayed方法很难准确地同步节拍。我使用ScheduledThreadPoolExecutor实现了精确的计时,但问题是,使用ScheduledThreadPoolExecutor,我无法从run方法中控制计时,因此我被迫停止并启动计划作业,这并不理想。有没有办法使处理程序更准确?还是一种不必停止和启动线程就可以重新调度ScheduledThreadPoolExecutor的方法 我目前的代码如下: public

我一直在尝试用Android编写节拍器,但是我发现使用Handler postdelayed方法很难准确地同步节拍。我使用ScheduledThreadPoolExecutor实现了精确的计时,但问题是,使用ScheduledThreadPoolExecutor,我无法从run方法中控制计时,因此我被迫停止并启动计划作业,这并不理想。有没有办法使处理程序更准确?还是一种不必停止和启动线程就可以重新调度ScheduledThreadPoolExecutor的方法

我目前的代码如下:

public class Metronome extends Service implements Runnable
{
    private Handler handler = new Handler();
    private SoundPool soundPool;
    private long interval;

    private void initSoundPool()
    {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            soundPool = new SoundPool.Builder()
                    .setMaxStreams(1)
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build())
                    .build();
        } else
        {
            soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
        }

        soundId = soundPool.load(context, R.raw.secondary_clave, 1);
    }

    @Override
    public void run()
    {
        handler.postDelayed(this, interval);
        soundPool.play(soundId, 1, 1, 0, 0, 1);
    }

    public void start()
    {
        handler.post(this);
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }
}
对于ScheduledThreadPoolExecutor,它非常精确,但是,我无法通过运行循环中的“interval”标志进行控制,因此如果我更改了interval,每次需要重新调度时,我都必须终止执行器并启动一个新的执行器,这太可怕了

public class Metronome extends Service implements Runnable
{        
    private SoundPool soundPool;
    private long interval;
    private ScheduledThreadPoolExecutor beatsPerBarExec;
    private ScheduledFuture<?> futureThread;

    private void initSoundPool()
    {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
        {
            soundPool = new SoundPool.Builder()
                    .setMaxStreams(1)
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .build())
                    .build();
        } else
        {
            soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
        }

        soundId = soundPool.load(context, R.raw.secondary_clave, 1);
    }

    @Override
    public void run()
    {            
        soundPool.play(soundId, 1, 1, 0, 0, 1);
    }

    public void start()
    {
        beatsPerBarExec = new ScheduledThreadPoolExecutor(1);
        futureThread = beatsPerBarExec.scheduleAtFixedRate(this, 0, interval, TimeUnit.MILLISECONDS);
    }

    public void pause()
    {
        futureThread.cancel(false);
        beatsPerBarExec.purge();
        beatsPerBarExec = null;            
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        return null;
    }
}
公共类Metronome扩展服务实现可运行
{        
私人声池声池;
私人长间隔;
私有ScheduledThreadPoolExecutor beatsPerBarExec;
私人计划未来;
私有void initSoundPool()
{
if(Build.VERSION.SDK\u INT>=Build.VERSION\u code.LOLLIPOP)
{
soundPool=新建soundPool.Builder()
.setMaxStreams(1)
.setAudioAttributes(新的AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT\u TYPE\u MUSIC)
.build())
.build();
}否则
{
soundPool=新的soundPool(1,AudioManager.STREAM_MUSIC,0);
}
soundId=soundPool.load(上下文,R.raw.secondary\u clave,1);
}
@凌驾
公开募捐
{            
soundPool.play(soundId,1,1,0,0,1);
}
公开作废开始()
{
beatsPerBarExec=新的ScheduledThreadPoolExecutor(1);
futuratRead=beatsPerBarExec.scheduleAtFixedRate(这个,0,间隔,时间单位,毫秒);
}
公共空间暂停()
{
futuratread.cancel(假);
beatsPerBarExec.purge();
beatsPerBarExec=null;
}
@凌驾
公共IBinder onBind(意向)
{
返回null;
}
}

您可能会看到漂移的影响

示例:您希望您的
Runnable
每200秒运行一次。使用
postDelayed()
run()
方法中重新安排
Runnable
,并将其作为延迟传递200秒。下次调用
run()
方法时,它可能不会比上次精确地200秒。也许是210毫秒。现在,您可以重新安排
Runnable
再运行200秒。这一次
run()

要消除漂移,您需要确定希望运行
Runnable
的确切时钟时间,减去当前时间,并在调用
postDelayed()
时使用该时间。这将考虑线程计时中的任何潜在差异

请注意,当您调用
postDelayed()
时,您正在发布一个
Runnable
以在主(UI)线程上运行。这是处理所有UI更新的线程,当
Runnable
准备好运行时,它将排队到主(UI)线程处理程序,并且可能不会立即运行

通过将
Runnable
调度为在后台线程而不是主(UI)线程上运行,可以缓解此问题。但是,这意味着您的
Runnable
将在后台线程上调用,我不知道您的其他代码(播放声音)是否需要在主(UI)线程上运行