🏷️ Request Tagging
KNETRequestTagging umożliwia tagowanie requestów
do grupowania, śledzenia i masowego anulowania.
💡 Kiedy używać?
- Anulowanie requestów przy onDestroy fragmentu/activity
- Grupowanie requestów per ekran/feature
- Śledzenie aktywnych requestów
- Analytics per tag
📦 Import
import rip.nerd.kitsunenet.util.KNETRequestTagging
import rip.nerd.kitsunenet.util.withTags
import rip.nerd.kitsunenet.util.withScreenTag
import rip.nerd.kitsunenet.util.getTags
🚀 Szybki start
val tagging = KNETRequestTagging.create()
// Taguj request
val request = KNETRequest.get("https://api.example.com/users")
.withTags("screen:home", "feature:users")
// Śledź request z jobem
val job = lifecycleScope.launch {
tagging.track(request, coroutineContext[Job]!!)
client.request(request)
}
// Anuluj wszystkie dla ekranu
tagging.cancelByTag("screen:home")
// Job zostanie anulowany
🏷️ Tagowanie requestów
// Jeden tag
val request = KNETRequest.get(url).withTags("users")
// Wiele tagów
val request = KNETRequest.get(url)
.withTags("screen:home", "feature:users", "priority:high")
// Helper dla ekranów
val request = KNETRequest.get(url)
.withScreenTag("HomeFragment")
// Helper dla feature
val request = KNETRequest.get(url)
.withFeatureTag("user-profile")
// Pobierz tagi
val tags = request.getTags()
// Set("screen:home", "feature:users")
// Sprawdź czy ma tag
if (request.hasTag("screen:home")) {
// ...
}
📌 Śledzenie requestów
// Śledzenie z Job (automatyczne untrack po zakończeniu)
val job = lifecycleScope.launch {
val requestId = tagging.track(request, coroutineContext[Job]!!)
client.request(request)
}
// Śledzenie bez Job (tylko grupowanie)
val requestId = tagging.track(request)
// Ręczne usunięcie z trackingu
tagging.untrack(requestId)
❌ Anulowanie
// Anuluj po tagu
val cancelled = tagging.cancelByTag("screen:home")
println("Anulowano: $cancelled requestów")
// Anuluj pasujące do WSZYSTKICH tagów
tagging.cancelByAllTags("screen:home", "feature:users")
// Anuluj pasujące do KTÓREGOKOLWIEK tagu
tagging.cancelByAnyTag("screen:home", "screen:profile")
// Anuluj wszystkie
tagging.cancelAll()
🔍 Zapytania
// Pobierz requesty z tagiem
val requests = tagging.getByTag("screen:home")
// Tylko aktywne
val active = tagging.getActiveByTag("screen:home")
// Sprawdź czy są aktywne
if (tagging.hasActiveByTag("screen:home")) {
showLoading()
}
// Policz aktywne
val count = tagging.countActiveByTag("screen:home")
println("Aktywnych: $count")
// Wszystkie aktywne tagi
val activeTags = tagging.getActiveTags()
// Wszystkie tagi
val allTags = tagging.getAllTags()
📊 Statystyki
val stats = tagging.getStats()
println("Total tracked: ${stats.totalTracked}")
println("Total cancelled: ${stats.totalCancelled}")
println("Active requests: ${stats.activeRequests}")
println("Tag count: ${stats.tagCount}")
// Requesty per tag
stats.requestsByTag.forEach { (tag, count) ->
println("$tag: $count")
}
🧹 Czyszczenie
// Usuń zakończone requesty z trackingu
tagging.cleanup()
// Wyczyść wszystko (anuluje aktywne)
tagging.clear()
💡 Praktyczne przykłady
Fragment z automatycznym anulowaniem
class UsersFragment : Fragment() {
private val tagging = KNETRequestTagging.instance
private val screenTag = "screen:${this::class.simpleName}"
private fun loadUsers() {
val request = KNETRequest.get("https://api.example.com/users")
.withTags(screenTag, "feature:users")
viewLifecycleOwner.lifecycleScope.launch {
tagging.track(request, coroutineContext[Job]!!)
try {
val response = client.request(request)
showUsers(response.jsonList())
} catch (e: CancellationException) {
// Anulowano - ignoruj
} catch (e: Exception) {
showError(e)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
// Anuluj wszystkie requesty tego ekranu
tagging.cancelByTag(screenTag)
}
}
ViewModel z tagowaniem
class HomeViewModel : ViewModel() {
private val tagging = KNETRequestTagging.instance
private val viewModelTag = "viewmodel:${this::class.simpleName}"
fun loadData() {
viewModelScope.launch {
val request = KNETRequest.get(url).withTags(viewModelTag)
tagging.track(request, coroutineContext[Job]!!)
// ...
}
}
override fun onCleared() {
super.onCleared()
tagging.cancelByTag(viewModelTag)
}
}
Global loading indicator
class GlobalLoadingManager(private val tagging: KNETRequestTagging) {
val isLoading: Boolean
get() = tagging.getStats().activeRequests > 0
fun isScreenLoading(screenName: String): Boolean {
return tagging.hasActiveByTag("screen:$screenName")
}
fun getLoadingScreens(): Set<String> {
return tagging.getActiveTags()
.filter { it.startsWith("screen:") }
.map { it.removePrefix("screen:") }
.toSet()
}
}
Priorytetowe anulowanie
// Gdy trzeba zwolnić zasoby - anuluj low priority
fun freeResources() {
tagging.cancelByTag("priority:low")
tagging.cancelByTag("priority:background")
}
// Zachowaj tylko krytyczne
fun keepOnlyCritical() {
tagging.cancelByAnyTag(
"priority:low",
"priority:normal",
"priority:high"
)
// priority:critical pozostaje
}
Feature flags
// Anuluj requesty dla wyłączonego feature
fun disableFeature(feature: String) {
tagging.cancelByTag("feature:$feature")
}
// Sprawdź czy feature ma aktywne requesty
fun isFeatureActive(feature: String): Boolean {
return tagging.hasActiveByTag("feature:$feature")
}
🔗 API Reference
KNETRequestTagging
| Metoda | Opis |
track(request, job) | Śledzi z anulowaniem |
track(request) | Śledzi bez job |
untrack(requestId) | Usuwa z trackingu |
cancelByTag(tag) | Anuluje po tagu |
cancelByAllTags(...) | Anuluje matching all |
cancelByAnyTag(...) | Anuluje matching any |
cancelAll() | Anuluje wszystkie |
getByTag(tag) | Pobiera po tagu |
getActiveByTag(tag) | Aktywne po tagu |
hasActiveByTag(tag) | Czy są aktywne |
countActiveByTag(tag) | Liczy aktywne |
getActiveTags() | Aktywne tagi |
getAllTags() | Wszystkie tagi |
getStats() | Statystyki |
cleanup() | Czyści zakończone |
clear() | Czyści wszystko |
Extensions
| Metoda | Opis |
request.withTags(...) | Dodaje tagi |
request.withScreenTag(name) | Tag ekranu |
request.withFeatureTag(name) | Tag feature |
request.getTags() | Pobiera tagi |
request.hasTag(tag) | Sprawdza tag |