Я просто опишу ответ Берги (в частности, вторую часть) немного, потому что мне очень понравилось, как это было сделано, но я хочу, чтобы опция останавливала таймер после его запуска ( как clearInterval()
почти). Sooo ... Я завернул его в конструктор, чтобы мы могли делать с ним «объективные» вещи.
Хорошо, поэтому вы копируете / вставляете это ...
/**
* Self-adjusting interval to account for drifting
*
* @param {function} workFunc Callback containing the work to be done
* for each interval
* @param {int} interval Interval speed (in milliseconds) - This
* @param {function} errorFunc (Optional) Callback to run if the drift
* exceeds interval
*/
function AdjustingInterval(workFunc, interval, errorFunc) {
var that = this;
var expected, timeout;
this.interval = interval;
this.start = function() {
expected = Date.now() + this.interval;
timeout = setTimeout(step, this.interval);
}
this.stop = function() {
clearTimeout(timeout);
}
function step() {
var drift = Date.now() - expected;
if (drift > that.interval) {
// You could have some default stuff here too...
if (errorFunc) errorFunc();
}
workFunc();
expected += that.interval;
timeout = setTimeout(step, Math.max(0, that.interval-drift));
}
}
Скажите, что делать и все это ...
// For testing purposes, we'll just increment
// this and send it out to the console.
var justSomeNumber = 0;
// Define the work to be done
var doWork = function() {
console.log(++justSomeNumber);
};
// Define what to do if something goes wrong
var doError = function() {
console.warn('The drift exceeded the interval.');
};
// (The third argument is optional)
var ticker = new AdjustingInterval(doWork, 1000, doError);
// You can start or stop your timer at will
ticker.start();
ticker.stop();
// You can also change the interval while it's in progress
ticker.interval = 99;
Я имею в виду, это работает для меня в любом случае. Если есть лучший способ, знаете ли.
Вы можете создать свой собственный абстрактный класс, который реализует ChildEventListener, но не обеспечивает реализацию onChildAdded:
abstract class ChildAddedEventListener : ChildEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onChildMoved(p0: DataSnapshot, p1: String?) {
}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {
}
override fun onChildRemoved(p0: DataSnapshot) {
}
}
Затем вы подклассифицируете ChildAddedEventListener и предоставляете только нужную реализацию:
class MyChildAddedEventListener: ChildAddedEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
// your code here
}
}
При этом вы можете использовать его как выражение встроенного объекта при добавлении его в запрос:
query.addChildEventListener(object : ChildAddedEventListener() {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
subscriber.onNext(Value.parse(unitName, varName, p0))
}
})
Вы можете сделать
object EmptyChildEventListener : ChildEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {}
override fun onChildMoved(p0: DataSnapshot, p1: String?) {}
override fun onChildRemoved(p0: DataSnapshot) {}
override fun onChildAdded(p0: DataSnapshot, p1: String?) { }
}
ref.addChildEventListener(object : ChildEventListener by EmptyChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
subscriber.onNext(Value.parse(unitName, varName, p0))
}
})
EDIT: но вы можете, возможно, улучшить это так, например
inline fun DatabaseReference.onChildAdded(crossinline added: (DataSnapshot, String?) -> Unit) {
this.addChildEventListener(object : ChildEventListener by EmptyChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) = added(p0, p1)
})
})
Теперь вы можете сделать
ref.onChildAdded { p0, p1 ->
subscriber.onNext(Value.parse(unitName, varName, p0))
}
Обычно имя шаблона, которое ommits всех методов называется Adapter, в вашем случае:
ref.addChildEventListener(object : ChildEventAdapter {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
subscriber.onNext(Value.parse(unitName, varName, p0))
}
})
Класс адаптера (интерфейса) - это класс, который реализует интерфейс с пустыми методами, поэтому вы может выбрать, какой из них вы хотите переопределить