Я пытался написать метроном на Android, однако мне очень трудно синхронизировать c удары точно с помощью метода Handler с задержкой. Мне удается добиться точного времени с помощью ScheduledThreadPoolExecutor, но проблема в том, что с помощью ScheduledThreadPoolExecutor я не могу контролировать время из метода выполнения, и поэтому я вынужден останавливать и запускать запланированное задание, что не идеально. Есть ли способ сделать задержку обработчика более точной? или способ перепланировать 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 он очень точен, однако я не У меня есть контроль с помощью флага «интервал» внутри прогона l oop, поэтому, если я изменю интервал, мне придется завершить выполнение исполнителя и начинать новый каждый раз, когда мне нужно перепланировать, что ужасно.
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;
}
}