1
1
package org.schabi.newpipe.player.ui
2
2
3
- import androidx.core. util.Consumer
3
+ import org.schabi.newpipe. util.GuardedByMutex
4
4
import java.util.Optional
5
5
6
6
class PlayerUiList (vararg initialPlayerUis : PlayerUi ) {
7
- val playerUis = mutableListOf<PlayerUi >()
7
+ var playerUis = GuardedByMutex ( mutableListOf<PlayerUi >() )
8
8
9
9
/* *
10
10
* Creates a [PlayerUiList] starting with the provided player uis. The provided player uis
@@ -16,7 +16,9 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
16
16
* @param initialPlayerUis the player uis this list should start with; the order will be kept
17
17
*/
18
18
init {
19
- playerUis.addAll(listOf (* initialPlayerUis))
19
+ playerUis.runWithLockSync {
20
+ lockData.addAll(listOf (* initialPlayerUis))
21
+ }
20
22
}
21
23
22
24
/* *
@@ -41,7 +43,9 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
41
43
}
42
44
}
43
45
44
- playerUis.add(playerUi)
46
+ playerUis.runWithLockSync {
47
+ lockData.add(playerUi)
48
+ }
45
49
}
46
50
47
51
/* *
@@ -52,12 +56,24 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
52
56
* @param T the class type parameter </T>
53
57
* */
54
58
fun <T > destroyAll (playerUiType : Class <T ?>) {
55
- for (ui in playerUis) {
56
- if (playerUiType.isInstance(ui)) {
57
- ui.destroyPlayer()
58
- ui.destroy()
59
- playerUis.remove(ui)
59
+ val toDestroy = mutableListOf<PlayerUi >()
60
+
61
+ // short blocking removal from class to prevent interfering from other threads
62
+ playerUis.runWithLockSync {
63
+ val new = mutableListOf<PlayerUi >()
64
+ for (ui in lockData) {
65
+ if (playerUiType.isInstance(ui)) {
66
+ toDestroy.add(ui)
67
+ } else {
68
+ new.add(ui)
69
+ }
60
70
}
71
+ lockData = new
72
+ }
73
+ // then actually destroy the UIs
74
+ for (ui in toDestroy) {
75
+ ui.destroyPlayer()
76
+ ui.destroy()
61
77
}
62
78
}
63
79
@@ -67,18 +83,19 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
67
83
* @param T the class type parameter
68
84
* @return the first player UI of the required type found in the list, or null
69
85
</T> */
70
- fun <T > get (playerUiType : Class <T >): T ? {
71
- for (ui in playerUis) {
72
- if (playerUiType.isInstance(ui)) {
73
- when (val r = playerUiType.cast(ui)) {
74
- // try all UIs before returning null
75
- null -> continue
76
- else -> return r
86
+ fun <T > get (playerUiType : Class <T >): T ? =
87
+ playerUis.runWithLockSync {
88
+ for (ui in lockData) {
89
+ if (playerUiType.isInstance(ui)) {
90
+ when (val r = playerUiType.cast(ui)) {
91
+ // try all UIs before returning null
92
+ null -> continue
93
+ else -> return @runWithLockSync r
94
+ }
77
95
}
78
96
}
97
+ return @runWithLockSync null
79
98
}
80
- return null
81
- }
82
99
83
100
/* *
84
101
* @param playerUiType the class of the player UI to return;
@@ -96,7 +113,11 @@ class PlayerUiList(vararg initialPlayerUis: PlayerUi) {
96
113
* @param consumer the consumer to call with player UIs
97
114
*/
98
115
fun call (consumer : java.util.function.Consumer <PlayerUi >) {
99
- for (ui in playerUis) {
116
+ // copy the list out of the mutex before calling the consumer which might block
117
+ val new = playerUis.runWithLockSync {
118
+ lockData.toMutableList()
119
+ }
120
+ for (ui in new) {
100
121
consumer.accept(ui)
101
122
}
102
123
}
0 commit comments