/*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 Damyan Ivanov.
* This file is part of MoLe.
* MoLe is free software: you can distribute it and/or modify it
* under the term of the GNU General Public License as published by
package net.ktnx.mobileledger.utils;
import android.os.Build;
-import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import org.jetbrains.annotations.NotNull;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
+import static net.ktnx.mobileledger.utils.Logger.debug;
public class ObservableList<T> extends Observable implements List<T> {
private List<T> list;
- private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private int notificationBlocks = 0;
+ private boolean notificationWasBlocked = false;
public ObservableList(List<T> list) {
this.list = list;
}
private void forceNotify() {
+ if (notificationBlocked()) return;
setChanged();
notifyObservers();
}
+ private boolean notificationBlocked() {
+ return notificationWasBlocked = (notificationBlocks > 0);
+ }
private void forceNotify(int index) {
+ if (notificationBlocked()) return;
setChanged();
notifyObservers(index);
}
throw new RuntimeException("Iterators break encapsulation and ignore locking");
// return list.iterator();
}
+ @NotNull
public Object[] toArray() {
try (LockHolder lh = lockForReading()) {
return list.toArray();
}
}
+ @Override
+ @NotNull
public <T1> T1[] toArray(@Nullable T1[] a) {
try (LockHolder lh = lockForReading()) {
return list.toArray(a);
try (LockHolder lh = lockForWriting()) {
boolean result = list.add(t);
lh.downgrade();
- if (result) forceNotify();
+ if (result)
+ forceNotify();
return result;
}
}
@NotNull
@RequiresApi(api = Build.VERSION_CODES.N)
public Spliterator<T> spliterator() {
- if (!lock.isWriteLockedByCurrentThread()) throw new RuntimeException(
- "Iterators break encapsulation and ignore locking. Write-lock first");
+ if (!lock.isWriteLockedByCurrentThread())
+ throw new RuntimeException(
+ "Iterators break encapsulation and ignore locking. Write-lock first");
return list.spliterator();
}
@RequiresApi(api = Build.VERSION_CODES.N)
- public boolean removeIf(Predicate<? super T> filter) {
+ public boolean removeIf(@NotNull Predicate<? super T> filter) {
try (LockHolder lh = lockForWriting()) {
boolean result = list.removeIf(filter);
lh.downgrade();
- if (result) forceNotify();
+ if (result)
+ forceNotify();
return result;
}
}
+ @NotNull
@RequiresApi(api = Build.VERSION_CODES.N)
public Stream<T> stream() {
if (!lock.isWriteLockedByCurrentThread()) throw new RuntimeException(
"Iterators break encapsulation and ignore locking. Write-lock first");
return list.stream();
}
+ @NotNull
@RequiresApi(api = Build.VERSION_CODES.N)
public Stream<T> parallelStream() {
- if (!lock.isWriteLockedByCurrentThread()) throw new RuntimeException(
- "Iterators break encapsulation and ignore locking. Write-lock first");
+ if (!lock.isWriteLockedByCurrentThread())
+ throw new RuntimeException(
+ "Iterators break encapsulation and ignore locking. Write-lock first");
return list.parallelStream();
}
@RequiresApi(api = Build.VERSION_CODES.N)
- public void forEach(Consumer<? super T> action) {
+ public void forEach(@NotNull Consumer<? super T> action) {
try (LockHolder lh = lockForReading()) {
list.forEach(action);
}
}
public List<T> getList() {
- if (!lock.isWriteLockedByCurrentThread()) throw new RuntimeException(
- "Direct list access breaks encapsulation and ignore locking. Write-lock first");
+ if (!lock.isWriteLockedByCurrentThread())
+ throw new RuntimeException(
+ "Direct list access breaks encapsulation and ignore locking. Write-lock first");
return list;
}
public void setList(List<T> aList) {
try (LockHolder lh = lockForReading()) {
int index = list.indexOf(item);
if (index == -1) {
- Log.d("ObList", "??? not sending notifications for item not found in the list");
+ debug("ObList", "??? not sending notifications for item not found in the list");
return;
}
- Log.d("ObList", "Notifying item change observers");
+ debug("ObList", "Notifying item change observers");
triggerItemChangedNotification(index);
}
}
rLock.lock();
return new LockHolder(rLock);
}
+ public void blockNotifications() {
+ notificationBlocks++;
+ }
+ public void unblockNotifications() {
+ notificationBlocks--;
+ if ((notificationBlocks == 0) && notificationWasBlocked) notifyObservers();
+ }
}
\ No newline at end of file