🏷️ 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

MetodaOpis
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

MetodaOpis
request.withTags(...)Dodaje tagi
request.withScreenTag(name)Tag ekranu
request.withFeatureTag(name)Tag feature
request.getTags()Pobiera tagi
request.hasTag(tag)Sprawdza tag

📚 Zobacz też