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.