X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Futils%2FObservableList.java;h=4ca3e695ae0a5d2cb9595fcd337fb62688129a6e;hb=20c03b7a5eb152d42fbbe9ecbaae27530563b398;hp=3add1bd488ce940c5f77a6db3a41306f64b254b2;hpb=c69d34015fc7087af67320b60aa1f6b3aa275b73;p=mobile-ledger-staging.git diff --git a/app/src/main/java/net/ktnx/mobileledger/utils/ObservableList.java b/app/src/main/java/net/ktnx/mobileledger/utils/ObservableList.java index 3add1bd4..4ca3e695 100644 --- a/app/src/main/java/net/ktnx/mobileledger/utils/ObservableList.java +++ b/app/src/main/java/net/ktnx/mobileledger/utils/ObservableList.java @@ -1,5 +1,5 @@ /* - * 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 @@ -18,7 +18,10 @@ 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; @@ -35,21 +38,26 @@ import java.util.function.Predicate; 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 extends Observable implements List { private List list; - private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private int notificationBlocks = 0; + private boolean notificationWasBlocked = false; public ObservableList(List 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); } @@ -73,11 +81,14 @@ public class ObservableList extends Observable implements List { 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[] toArray(@Nullable T1[] a) { try (LockHolder lh = lockForReading()) { return list.toArray(a); @@ -87,7 +98,8 @@ public class ObservableList extends Observable implements List { try (LockHolder lh = lockForWriting()) { boolean result = list.add(t); lh.downgrade(); - if (result) forceNotify(); + if (result) + forceNotify(); return result; } } @@ -226,40 +238,46 @@ public class ObservableList extends Observable implements List { @NotNull @RequiresApi(api = Build.VERSION_CODES.N) public Spliterator 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 filter) { + public boolean removeIf(@NotNull Predicate 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 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 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 action) { + public void forEach(@NotNull Consumer action) { try (LockHolder lh = lockForReading()) { list.forEach(action); } } public List 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 aList) { @@ -273,10 +291,10 @@ public class ObservableList extends Observable implements List { 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); } } @@ -297,4 +315,11 @@ public class ObservableList extends Observable implements List { 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