Úlohy pre 7. cvičenie

  • 1. Zamyslenie sa nad Social computing a Gamifikáciou
  • 2. Workmanager
  • 3. Notifikácie

Hodnotenie

Za splnenie všetkých úloh celkovo 2 body.

2. Workmanager

1. Úvod do WorkManagera

WorkManager je knižnica určená na plánovanie odložiteľných úloh na pozadí, zabezpečuje vykonanie úloh aj keď je aplikácia zatvorená alebo zariadenie reštartované. Je vhodný pre úlohy ako nahrávanie logov, aplikovanie filtrov na obrázky alebo pravidelná synchronizácia lokálnych dát so sieťou.

2. Pridanie WorkManagera do vášho projektu

Pridajte závislosť WorkManager do vášho súboru app/build.gradle:


dependencies {
    implementation "androidx.work:work-runtime-ktx:$versions.work"
}
                
Synchronizujte svoj projekt, aby sa zabezpečilo, že závislosť je správne načítaná.

3. Vytvorenie vašej prvej práce

Definujte triedu Worker, aby ste určili prácu, ktorú chcete vykonať:


import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {
    
    override fun doWork(): Result {
        // Tu môžete vykonávať synchrónnu prácu

        return Result.success()
    }
}
                

Alebo pre asynchrónne úlohy (suspend):


import androidx.work.Worker
import androidx.work.WorkerParameters

class MyWorker(appContext: Context, workerParams: WorkerParameters)
    : CoroutineWorker(appContext, workerParams) {
    
    override suspend fun doWork(): Result {
        // Tu môžete vykonávať asynchrónnu prácu

        return Result.success()
    }
}
                
Vytvorte WorkRequest, aby ste nakonfigurovali, ako a kedy spustiť vašu prácu jednorazovo:

val myWorkRequest = OneTimeWorkRequestBuilder<MyWorker>().build()
                
Zaradte vašu prácu do WorkManagera:

WorkManager.getInstance(myContext).enqueue(myWorkRequest)
                

Zdroj obrazka: https://developer.android.com/guide/background/persistent/how-to/states

Alternatívne vytvorte WorkRequest, aby ste spustili vašu prácu opakovane:


val repeatingRequest = PeriodicWorkRequestBuilder<MyWorker>(
1, TimeUnit.HOURS, // repeatInterval
15, TimeUnit.MINUTES // flexInterval
).build()
                
Zaradte vašu prácu do WorkManagera:

WorkManager.getInstance(myContext).enqueueUniquePeriodicWork(
"Unique Name",
ExistingPeriodicWorkPolicy.KEEP, // or REPLACE
repeatingRequest
)
                

Zdroj obrazka: https://developer.android.com/guide/background/persistent/how-to/states

4. Podmienky spustenia

Nastavte obmedzenia, aby ste určili podmienky, za ktorých by sa mala vaša práca spustiť:


val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .build()

val myWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
    .setConstraints(constraints)
    .build()
                

Nastavenie oneskoreného spustenia.

				 
val myWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
   .setInitialDelay(10, TimeUnit.MINUTES)
   .build()
   

Nastavenie politiky opakovania sa neúspešnej úlohy ( doWork() musí vrátiť Result.retry() )

	
 val myWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
   .setBackoffCriteria(
       BackoffPolicy.LINEAR,
       OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
       TimeUnit.MILLISECONDS)
   .build()

5. Vstupne a vystupne data

Definovanie vstupných dát:


val inputData = workDataOf("key1" to "value1", "key2" to 2)

val myWorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
    .setInputData(inputData)
    .build()
                

Prístup k vstupným dátam vo vašom Workeri:


class MyWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {
    
    override fun doWork(): Result {
        val inputData = inputData
        val value1 = inputData.getString("key1")
        val value2 = inputData.getInt("key2", 0)

        // Do the work here

        return Result.success()
    }
}
                

Definovanie výstupných dát:


class MyWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {
    
    override fun doWork(): Result {
        // Do the work here

        val outputData = workDataOf("outputKey" to "outputValue")

        return Result.success(outputData)
    }
}
                

6. Odovzdavanie parametrov

Prístup k výstupným dátam v nasledujúcom Worker-i:


class FirstWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {
    
    override fun doWork(): Result {
        // Do the work here
        val inputData = inputData
        val value1 = inputData.getInt("key1", 0)
        val value2 = inputData.getInt("key2", 0)
		
        val outputData = workDataOf("outputKey" to value1+value2)

        return Result.success(outputData)
    }
}

class SecondWorker(appContext: Context, workerParams: WorkerParameters)
    : Worker(appContext, workerParams) {
    
    override fun doWork(): Result {
        val inputData = inputData
        val value1 = inputData.getString("outputKey")

        // Do the work here

        return Result.success()
    }
}

val inputData = workDataOf("key1" to 3, "key2" to 2)

val firstRequest = OneTimeWorkRequestBuilder<FirstWorker>().setInputData(inputData).build()
val secondRequest = OneTimeWorkRequestBuilder<SecondWorker>().setInputMerger(OverwritingInputMerger::class).build()

WorkManager.getInstance(myContext)
    .beginWith(firstRequest)
    .then(secondRequest)
    .enqueue()
                

7. Možné návratové stavy z metódy doWork()

Metóda doWork() v triede Worker môže vrátiť tri rôzne stavy, ktoré oznámia WorkManageru výsledok vykonávania práce. Tieto stavy sú:

1. Result.success():


override fun doWork(): Result {
    // ... your code ...

    return Result.success() // alebo Result.success(data)
}
                
Tento stav označuje, že práca bola úspešne dokončená.

2. Result.failure():


override fun doWork(): Result {
    // ... your code ...

    return Result.failure() // alebo Result.failure(data)
}
                
Tento stav označuje, že práca zlyhala a nemala by sa pokúsiť znova.

3. Result.retry():


override fun doWork(): Result {
    // ... your code ...

    return Result.retry()  
}
                
Tento stav označuje, že práca zlyhala, ale mala by sa pokúsiť znova neskôr.

8. Úprava existujúceho WorkRequestu

Úprava existujúceho WorkRequestu (používa sa len vo špeciálnych prípadoch) :

suspend fun updatePhotoUploadWork() {
    // Get instance of WorkManager.
    val workManager = WorkManager.getInstance(context)

    // Retrieve the work request ID. In this example, the work being updated is unique
    // work so we can retrieve the ID using the unique work name.
    val photoUploadWorkInfoList = workManager.getWorkInfosForUniqueWork(
        PHOTO_UPLOAD_WORK_NAME
    ).await()

    val existingWorkRequestId = photoUploadWorkInfoList.firstOrNull()?.id ?: return

    // Update the constraints of the WorkRequest to not require a charging device.
    val newConstraints = Constraints.Builder()
        // Add other constraints as required here.
        .setRequiresCharging(false)
        .build()

    // Create new WorkRequest from existing Worker, new constraints, and the id of the old WorkRequest.
    val updatedWorkRequest: WorkRequest =
        OneTimeWorkRequestBuilder<MyWorker>()
            .setConstraints(newConstraints)
            .setId(existingWorkRequestId)
            .build()

    // Pass the new WorkRequest to updateWork().
    workManager.updateWork(updatedWorkRequest)
}

9. Monitorovanie a ladenie

Použite logcat v Android Studio na sledovanie logov WorkManagera.

3. Notifikácie

1. Povolenia pre zobrazenie oznámenia

Od verzie Android 13 je potrebné získať povolenie od používateľa pred tým, ako mu môžete zaslať oznámenia. Tento model pomáha znížiť prerušenia oznámení, minimalizovať preťaženie informáciami a pomáha používateľom kontrolovať, ktoré oznámenia sa zobrazia na základe toho, čo je pre nich dôležité.

Pre získanie povolenia na zobrazenie oznámení je potrebné pridať nasledujúci riadok do vášho AndroidManifest.xml súboru:


<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
            

Toto povolenie je nevyhnutné, aby vaša aplikácia mohla zobrazovať oznámenia používateľom. Následne pre Android 13 musíte vyžiadať povolenie na zobrazenie notifikácií od používateľa rovnako ako pri GPS polohe. Najlepšie to urobiť hneď spolu so žiadaním povolenia o GPS polohu.

2. Vytvorenie Notification Channel (Kanála oznámení)

Pred zobrazením oznámenia je potrebné vytvoriť Notification Channel.

// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val name = "MOBV Zadanie"
    val descriptionText = "Popis notifikacie"
    val importance = NotificationManager.IMPORTANCE_DEFAULT
	val channel_id = "kanal-1"
    val channel =
        NotificationChannel(channel_id, name, importance).apply {
            description = descriptionText
        }
    // Register the channel with the system
    val notificationManager: NotificationManager =
        appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    notificationManager.createNotificationChannel(channel)
}

3. Zobrazenie oznámenia

Aby ste mohli zobraziť oznámenia z Worker-a, je potrebné najprv vytvoriť základné oznámenie pomocou objektu NotificationCompat.Builder. Toto oznámenie môže zobrazovať ikonu, názov a malé množstvo textového obsahu, ktoré môže používateľ ťuknúť na spustenie aktivity vo vašej aplikácii. Oznámenia sú správy, ktoré Android zobrazuje mimo rozhrania vašej aplikácie, aby poskytol používateľovi pripomienky, komunikáciu od iných osôb alebo iné aktuálne informácie z vašej aplikácie.

Tu je príklad kódu v jazyku Kotlin, ktorý demonštruje, ako vytvoriť a zobraziť oznámenie:

val name = "MOBV Zadanie"
val descriptionText = "Popis notifikacie"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel_id = "kanal-1"
val builder =
    NotificationCompat.Builder(appContext, channel_id).apply {
        setContentTitle("Titulok")
        setContentText("Text notifikacie")
        setSmallIcon(R.drawable.ikona_notifikacie)
        priority = NotificationCompat.PRIORITY_DEFAULT
    }

if (ActivityCompat.checkSelfPermission(
        appContext,
        Manifest.permission.POST_NOTIFICATIONS
    ) != PackageManager.PERMISSION_GRANTED
) {
    Log.d("Notifikacia","Chyba povolenie na notifikaciu");
    return
}

NotificationManagerCompat.from(context).notify(1, builder.build())

Vytvorenie kanála a zobrazenie notifikácie môže urobiť vo vnútri Workera (alebo Fragmentu či BroadcastReceivera).