WorkManager
Uso de WorkManager
What WorkManager is and when to use WorkManager
How to use the WorkManager API to schedule Work
Android WorkManager Tutorial: Getting Started
Crear un proyecto llamado WorkManagerDownload
dar permisos en el manifiesto
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
añadir view binding en el build.gradle del módulo
buildFeatures {
viewBinding = true
}
usar la versión 17 de Java
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
añadir la dependencia de WorkManager y corutinas
// WorkManager dependency
// implementation("androidx.work:work-runtime-ktx:2.10.0")
implementation(libs.androidx.work.runtime.ktx)
// Coroutines dependency
// implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
implementation(libs.kotlinx.coroutines.core)
crear la clase DownloadWorker con la tarea a realizar
class DownloadWorker(appContext: Context, params: WorkerParameters) : CoroutineWorker(appContext, params) {
companion object {
private const val TAG = "DownloadWorker"
const val KEY_WEB_URL = "web_url"
const val KEY_FILE_NAME = "file_name"
const val KEY_FILE_PATH = "file_path"
const val ERROR_MESSAGE = "error_message"
}
override suspend fun doWork(): Result {
val webUrl = inputData.getString(KEY_WEB_URL) ?: return Result.failure()
val fileName = inputData.getString(KEY_FILE_NAME) ?: return Result.failure()
return try {
Thread.sleep(5000)
val route = withContext(Dispatchers.IO) {
downloadFile(webUrl, fileName)
}
val outputData = workDataOf(KEY_FILE_PATH to route)
Result.success(outputData)
} catch (e: Exception) {
Log.e(TAG, "Error downloading file: ${e.message}", e)
val outputData = workDataOf(ERROR_MESSAGE to "Download failed: ${e.message}")
Result.failure(outputData)
}
}
private fun downloadFile(url: String, fileName: String): String {
val url = URL(url)
val connection = url.openConnection()
connection.connect()
val inputStream = BufferedInputStream(connection.getInputStream())
val file = File(applicationContext.getExternalFilesDir(null), fileName) // Or use internal storage: File(applicationContext.filesDir, fileName)
val outputStream = FileOutputStream(file)
inputStream.copyTo(outputStream)
outputStream.close()
inputStream.close()
return file.absolutePath
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Uso de WorkManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.096" />
<Button
android:id="@+id/botonIniciar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="Iniciar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.535"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<Button
android:id="@+id/botonParar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Parar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.534"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/botonIniciar"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/salida"
android:layout_width="260dp"
android:layout_height="120dp"
android:layout_marginTop="44dp"
android:text="resultado de la descarga"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.582"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/botonParar"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
class MainActivity : AppCompatActivity(), View.OnClickListener {
lateinit var binding: ActivityMainBinding
lateinit var downloadWorkRequest: OneTimeWorkRequest
// lateinit var downloadWorkRequest: PeriodicWorkRequest
var start: Boolean = false
companion object {
const val WEB = "https://dam.org.es/ficheros/frases.html"
const val FILE_NAME = "frases.html"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
*/
binding = ActivityMainBinding.inflate(layoutInflater)
val view: View = binding.root
setContentView(view)
binding.botonIniciar.setOnClickListener(this)
binding.botonParar.setOnClickListener(this)
}
override fun onClick(v: View) {
binding.salida.text = ""
if (v == binding.botonIniciar) {
startDownload(WEB, FILE_NAME)
start = true
binding.botonIniciar.isEnabled = false
}
if (v == binding.botonParar)
if (start) {
mostrarMensaje(downloadWorkRequest.id.toString() + " parado")
Log.i("Parar", downloadWorkRequest.id.toString() + " parado")
WorkManager.getInstance(this).cancelWorkById(downloadWorkRequest.id)
start = false
binding.botonIniciar.isEnabled = true
}
}
private fun mostrarMensaje(mensaje: String) {
Toast.makeText(this, mensaje, Toast.LENGTH_SHORT).show()
}
private fun startDownload(webUrl: String, fileName: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val inputWorkData = workDataOf(
DownloadWorker.KEY_WEB_URL to webUrl,
DownloadWorker.KEY_FILE_NAME to fileName
)
downloadWorkRequest = OneTimeWorkRequestBuilder<DownloadWorker>()
.setConstraints(constraints)
.setInputData(inputWorkData)
.build()
// downloadWorkRequest = PeriodicWorkRequestBuilder<DownloadWorker>(1, TimeUnit.HOURS).build()
WorkManager.getInstance(this).enqueue(downloadWorkRequest)
// You can observe the work's progress and output if needed:
WorkManager.getInstance(this).getWorkInfoByIdLiveData(downloadWorkRequest.id)
.observe(this) {
workInfo ->
when (workInfo?.state) {
WorkInfo.State.SUCCEEDED -> {
val filePath = workInfo.outputData.getString(DownloadWorker.KEY_FILE_PATH)
// Do something with the downloaded file path
Log.d("Download", "File downloaded to: $filePath")
mostrarMensaje(filePath.toString())
binding.salida.text = filePath.toString()
binding.botonIniciar.isEnabled = true
}
WorkInfo.State.FAILED -> {
// Handle failure
val errorMessage = workInfo.outputData.getString(DownloadWorker.ERROR_MESSAGE)
// Do something with the error message
Log.e("Download", "Download failed: $errorMessage")
mostrarMensaje(errorMessage.toString())
binding.salida.text = errorMessage.toString()
binding.botonIniciar.isEnabled = true
}
// ... other states (RUNNING, ENQUEUED, etc.)
WorkInfo.State.ENQUEUED ->
mostrarMensaje("Enqueued")
WorkInfo.State.RUNNING ->
mostrarMensaje("Running")
WorkInfo.State.BLOCKED ->
mostrarMensaje("Blocked")
WorkInfo.State.CANCELLED ->
mostrarMensaje("Cancelled")
else ->
mostrarMensaje("Otro estado")
}
}
}
public override fun onDestroy() {
super.onDestroy()
//cancelar los trabajos con WorkManager
// if (start)
// WorkManager.getInstance().cancelAllWork()
WorkManager.getInstance(this).cancelAllWork()
}
}
Más información:
Codelab: Trabajo en segundo plano con WorkManager
Workout your tasks with WorkManager


Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.