接口文档示例_在示例中使用Android中的Work Manager

接口文档示例

接口文档示例

在本文中,我们将介绍如何在android中使用工作管理器。 工作管理器是android体系结构组件的一部分,并且可以很好地替代所有先前的调度选项。

其他调度选项,例如JobScheduler,GcmNetworkManager等。但是它们有缺点。 GcmNetworkManager需要播放服务,因此它不适用于某些中国OEM和JobScheduler支持的API> 21。

但是android中的工作管理器可以优雅地解决所有这些问题。 到目前为止,它是Android中最易于使用的API之一。

在此工作管理器示例中,我们将创建一个应用程序来使用工作管理器在后台下载3张图像并将其添加到列表中。

警告:不应将工作管理器用于诸如单击按钮下载某些内容之类的任务。 它仅应用于DEFERRABLE任务。 但是为了简单起见,我举了这个例子。

我要命名我的项目工作经理演示。 您可以随意命名。 确保选择一个空的活动。 我们将从头开始编写所有内容。

让我们添加一些依赖性。 首先是工作经理。 然后,为该示例添加一些额外的依赖项。 它包括Picasso,Gson和EventBus。

 implementation "androidx.work:work-runtime-ktx:2.4.0"
 implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
 implementation 'com.google.code.gson:gson:2.8.5'
 implementation 'com.squareup.picasso:picasso:2.71828'
 implementation 'com.squareup.okhttp3:okhttp:3.13.1'
 implementation 'org.greenrobot:eventbus:3.1.1'

撰写本文时,最新版本为2.4.0,您可以在developers.android.com上找到最新版本。 或者只是搜索工作经理的依赖关系,它将是第一个链接。

下图显示了我们应用程序的基本流程。 主要是我们会有一个工作程序(在以下各节中将对此进行解释),一个ImageUtil类来下载图像,以及我们的MainActivity来启动该过程。

这个应用程序的用户界面将非常简单,它是一个带有3个图像视图的滚动视图。 底部的一个按钮可启动工作管理器。

 <?xml version= "1.0" encoding= "utf-8" ?>
 <LinearLayout 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"

    android:orientation= "vertical"

    tools:context= ".MainActivity" > 
    <ScrollView

        android:layout_width= "match_parent"

        android:layout_height= "0dp"

        android:layout_weight= "1" > 
        <LinearLayout

            android:layout_width= "match_parent"

            android:layout_height= "match_parent"

            android:layout_weight= "1"

            android:gravity= "center_horizontal"

            android:orientation= "vertical" > 
            <ImageView

                android:id= "@+id/iv_1"

                android:layout_width= "300dp"

                android:layout_height= "300dp"

                android:layout_marginTop= "32dp"

                android:scaleType= "fitXY" /> 
            <ImageView

                android:id= "@+id/iv_2"

                android:layout_width= "300dp"

                android:layout_height= "300dp"

                android:layout_marginTop= "32dp"

                android:scaleType= "fitXY" /> 
            <ImageView

                android:id= "@+id/iv_3"

                android:layout_width= "300dp"

                android:layout_height= "300dp"

                android:layout_marginTop= "32dp"

                android:scaleType= "fitXY" /> 
        </LinearLayout>

    </ScrollView>

    <Button

        android:id= "@+id/btn_download"

        android:layout_width= "match_parent"

        android:layout_height= "wrap_content"

        android:layout_gravity= "bottom"

        android:text= "Start Download" />
 </LinearLayout>

将下面提供的JSON添加到MainActivity.kt文件的顶部。 这将包含要下载图像的URL。

 val jsonString: String = "[\n" +

        " {\n" +

        "   \"albumId\": 1,\n" +

        "   \"id\": 1,\n" +

        "   \"title\": \"Eminem\",\n" +

        "   \"url\": \" https://i.pinimg.com/originals/c4/14/4f/c4144fba258c2f0b4735180fe5d9a03b.jpg \",\n" +

        "   \"thumbnailUrl\": \" https://via.placeholder.com/150/92c952 \"\n" +

        " },\n" +

        " {\n" +

        "   \"albumId\": 1,\n" +

        "   \"id\": 2,\n" +

        "   \"title\": \"MEME\",\n" +

        "   \"url\": \" https://pics.me.me/eminems-emotions-suprised-sad-happy-curious-annoyed-excited-shocked-bored-13877943.png \",\n" +

        "   \"thumbnailUrl\": \" https://via.placeholder.com/150/771796 \"\n" +

        " },\n" +

        " {\n" +

        "   \"albumId\": 1,\n" +

        "   \"id\": 3,\n" +

        "   \"title\": \"Eminem News\",\n" +

        "   \"url\": \" https://www.sohh.com/wp-content/uploads/Eminem.jpg \",\n" +

        "   \"thumbnailUrl\": \" https://via.placeholder.com/150/24f355 \"\n" +

        " }]"

另外,让我们继续,然后在按钮上添加一个点击侦听器。 单击按钮后,我们将调用方法startWorker() 。 现在,这就是乐趣的开始!

 override fun onCreate(savedInstanceState: Bundle?) {

    super .onCreate(savedInstanceState)

    setContentView(R.layout.activity_main)

    btn_download.setOnClickListener {

        startWorker()

    }
 }
 private fun startWorker() {
 }

工作管理器需要一个包含我们要执行的任务的工作器。 我们要做的是,将JSON传递给工作人员,然后工作人员将下载所有图像。

要在工作管理器中传递数据,我们必须使用由工作管理器在android中提供的特殊数据对象。 以下是创建数据对象的方法:

 private fun startWorker() {

    val data = Data.Builder()

        .putString( "images" , jsonString)

        .build()
 }

数据采用所有原始类型。 因此,我们使用putString方法。

非常重要:数据限制为10KB。 如果您尝试传递位图之类的东西(通过转换为Base64),它将失败。 因此,在将数据传递给工作人员时要非常谨慎。

约束是工作管理器的一项非常强大的功能。 它允许我们指定某些条件才能开始工作。

如果不满足条件,则无论我们是否以代码形式启动过程,都将无法开始工作。

不能保证工作经理会在正确的时间开始您的工作。 因此,诸如下载之类的任务应使用android中的DownloadManager完成。 仅将工作管理器用于可延期的任务。 例如:在后台同步日志,备份聊天等…。

要添加约束,您需要做的就是使用构建器模式构建约束对象,如下所示:

 private fun startWorker() {

    val data = Data.Builder()

        .putString( "images" , jsonString)

        .build()

    val constraints = Constraints.Builder()

        .setRequiredNetworkType(NetworkType.CONNECTED)
 }

您可以指定许多约束,例如:

  1. 要求设备空闲:仅在设备空闲且未使用时才触发工作。
  2. 需要充电:仅在插入手机进行充电时才会触发。
  3. 电池电量不足:要求电池电量在一定水平。
  4. 存储空间不低:存储空间不应该低

您可以在以下位置找到所有约束: developer.android.com

我们将创建一个一次性请求。 顾名思义,它将触发一次并停止。 如果要安排定期任务,请考虑使用PreiodicWorkRequest。

使用OneTimeRequest中的构建器模式。 在构建器构造函数中传递ImageDownloadWorker :: class.java。 我们将在下一部分中创建工作程序。

还使用构建器函数传递数据和约束:

 private fun startWorker() {

    val data = Data.Builder()

        .putString( "images" , jsonString)

        .build()

    val constraints = Constraints.Builder()

        .setRequiredNetworkType(NetworkType.CONNECTED)

    val oneTimeRequest = OneTimeWorkRequest.Builder(ImageDownloadWorker:: class .java)

        .setInputData(data)

        .setConstraints(constraints.build())

        .addTag( "demo" )

        .build()
 }

这将创建我们的OneTimeRequest

最后,我们可以如下启动工作程序:

 private fun startWorker() {

    val data = Data.Builder()

        .putString( "images" , jsonString)

        .build()

    val constraints = Constraints.Builder()

        .setRequiredNetworkType(NetworkType.CONNECTED)

    val oneTimeRequest = OneTimeWorkRequest.Builder(ImageDownloadWorker:: class .java)

        .setInputData(data)

        .setConstraints(constraints.build())

        .addTag( "demo" )

        .build()

    Toast.makeText( this , "Starting worker" , Toast.LENGTH_SHORT).show() 
    WorkManager.getInstance( this )

        .enqueueUniqueWork( "AndroidVille" , ExistingWorkPolicy.KEEP, oneTimeRequest)
 }

我们获得了工作经理的实例,然后将工作加入队列。 传递唯一的工作名称。 这将用于将来的工作。 如果您将其他作品与此作品相加。

接下来,我们告诉我们要使用什么ExistingPolicyExistingPolicy定义了如果已经存在同名作品会发生什么。

可以使用4种策略:

  1. 替换:如果已经存在同名作品,请用此新作品替换它。 先前的工作将停止并删除。
  2. 保持:如果已经存在同名作品,则什么也不做。 原始工作将继续进行。
  3. 追加:将新作品追加到已经存在的作品中。
  4. APPEND_OR_REPLACE:如果以前的工作失败,它将创建一个新序列,否则其行为类似于APPEND。

最后,我们传递请求对象。 这将触发工作管理器,并且如果满足条件,它将启动ImageDownloadWorker。 让我们继续创造工人。

我们的工人将做两件事:

  1. 下载图像。
  2. 显示进度通知。

要创建工作程序,请创建一个名为ImageDownloadWorker.kt的类,然后从“工作程序”中进行扩展。

 class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {
 }

实现doWork方法。 这是我们工作的起点。 首先,让我们继续进行下载。

 class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {

    override fun doWork(): Result {

    }
 }

使用inputData.getString获取您在MainActivity中传递的JSON数据:

 class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {

    @SuppressLint ( "RestrictedApi" , "CheckResult" )

    override fun doWork(): Result {

        val imagesJson = inputData.getString( "images" ) 
        return Result.Success()

    }
 }

我们将使用Gson将其转换为图像对象列表。 图像是我创建的用于轻松存储有关图像信息的数据类。

 class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {

    @SuppressLint ( "RestrictedApi" , "CheckResult" )

    override fun doWork(): Result {

        val imagesJson = inputData.getString( "images" )

        val gson = Gson()

        val listOfImages = gson.fromJson<List<Image>>(imagesJson, object : TypeToken<List<Image>>() {}.type);

        listOfImages.forEachIndexed { index, image ->

            Thread.sleep( 1000 ) //emulating network call.

            downloadImage(image, index)

        }

        return Result.Success()

    }
 }

图片类:

data class Image(var albumId: String, var id: String, var title: String, var url: String, var thumbnail: String)

接下来,我们将遍历每个图像对象,下载图像并将其存储在我们的存储中。 将以下下载功能添加到您的工作程序中:

 private fun downloadImage(image: Image, index: Int) {

    val client = OkHttpClient()

    val request = Request.Builder()

        .url(image.url)

        .build()

    try {

        val response = client.newCall(request).execute()

        val bitmap = BitmapFactory.decodeStream(response.body()?.byteStream())

        ImageUtil.saveBitmap(mContext, bitmap, image.title).subscribe({ img ->

            displayNotification(ProgressUpdateEvent(image.title, 3 , index + 1 ))

            EventBus.getDefault().post(ImageDownloadedEvent(img, image.title, image.id))

        }, { error ->

            error.printStackTrace()

        })

    } catch (e: Exception) {

        e.printStackTrace()

    }
 }

它使用下面提供的ImageUtil类。 我创建它是为了保持我分开下载图像的逻辑。 创建一个新的ImageUtil类,并添加以下代码:

 package com.example.workmanagerdemo
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Bitmap
 import io.reactivex.Observable
 import io.reactivex.Single
 import java.io.ByteArrayOutputStream
 import java.io.File
 import java.io.FileOutputStream
 import java.io.IOException
 object ImageUtil {

    @SuppressLint ( "CheckResult" )

    fun saveBitmap(context: Context, bitmap: Bitmap, filename: String): Single<String> {

        return Single.create<String> { emitter ->

            val stream = ByteArrayOutputStream()

            bitmap.compress(Bitmap.CompressFormat.JPEG, 30 , stream)

            val mediaByteArray = stream.toByteArray()

            try {

                val myDir = context.filesDir

                val path = "$myDir/media/"

                val secondFile = File( "$myDir/media/" , filename) 
                if (!secondFile.parentFile.exists()) {

                    secondFile.parentFile.mkdirs()

                }

                secondFile.createNewFile()

                val fos = FileOutputStream(secondFile)

                fos.write(mediaByteArray)

                fos.flush()

                fos.close()

                emitter.onSuccess(path)

            } catch (exception: IOException) {

                exception.printStackTrace()

                emitter.onError(exception)

            }

        }

    }
 }

要显示进度通知,请向您的工作人员添加以下方法。 还要在doWork方法的开始处调用它。

 class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {

    private val notificationManager =

        applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    @SuppressLint ( "RestrictedApi" , "CheckResult" )

    override fun doWork(): Result {

        Log.d( "AndroidVille" , Thread.currentThread().toString())

        displayNotification(ProgressUpdateEvent( "Please wait..." , 3 , 0 )) 
        val imagesJson = inputData.getString( "images" )

        val gson = Gson()

        val listOfImages = gson.fromJson<List<Image>>(imagesJson, object : TypeToken<List<Image>>() {}.type);

        listOfImages.forEachIndexed { index, image ->

            Thread.sleep( 1000 ) //emulating network call.

            downloadImage(image, index)

        }

        notificationManager.cancel(notificationId)

        return Result.Success()

    }

    private val notificationId: Int = 500

    private val notificationChannel: String = "demo" 
    private fun displayNotification(prog: ProgressUpdateEvent) {

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

            val channel = NotificationChannel(

                notificationChannel,

                notificationChannel,

                NotificationManager.IMPORTANCE_DEFAULT

            )

            channel.enableVibration( false )

            notificationManager.createNotificationChannel(channel)

        }

        val notificationBuilder =

            NotificationCompat.Builder(applicationContext, notificationChannel)

        val remoteView = RemoteViews(applicationContext.packageName, R.layout.custom_notif)

        remoteView.setImageViewResource(R.id.iv_notif, R.drawable.eminem)

        remoteView.setTextViewText(R.id.tv_notif_progress, "${prog.message} (${prog.progress}/${prog.total} complete)" )

        remoteView.setTextViewText(R.id.tv_notif_title, "Downloading Images" )

        remoteView.setProgressBar(R.id.pb_notif, prog.total, prog.progress, false ) 
        notificationBuilder

            .setContent(remoteView)

            .setSmallIcon(R.drawable.eminem)

        notificationManager.notify(notificationId, notificationBuilder.build())

    }

    data class ProgressUpdateEvent(var message: String, var total: Int, var progress: Int)
 }

当工作人员停止时,我们还必须取消通知。 因此,重写onStopped方法并添加以下内容:

 override fun onStopped() {

    super .onStopped()

    notificationManager.cancel(notificationId)
 }

我们完成了! 最后,这是您的ImageDownloadWorker文件的外观:

 package com.example.workmanagerdemo
 import android.annotation.SuppressLint
 import android.app.NotificationChannel
 import android.app.NotificationManager
 import android.content.Context
 import android.graphics.BitmapFactory
 import android.util.Log
 import android.widget.RemoteViews
 import androidx.core.app.NotificationCompat
 import androidx.work.Worker
 import androidx.work.WorkerParameters
 import com.google.gson.Gson
 import com.google.gson.reflect.TypeToken
 import io.reactivex.Observable
 import okhttp3.OkHttpClient
 import okhttp3.Request
 import org.greenrobot.eventbus.EventBus
 import java.util.concurrent.TimeUnit  class ImageDownloadWorker( private val mContext: Context, workerParameters: WorkerParameters) :

    Worker(mContext, workerParameters) {

    private val notificationManager =

        applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    @SuppressLint ( "RestrictedApi" , "CheckResult" )

    override fun doWork(): Result {

        Log.d( "AndroidVille" , Thread.currentThread().toString())

        displayNotification(ProgressUpdateEvent( "Please wait..." , 3 , 0 ))

        val imagesJson = inputData.getString( "images" )

        val gson = Gson()

        val listOfImages = gson.fromJson<List<Image>>(imagesJson, object : TypeToken<List<Image>>() {}.type);

        listOfImages.forEachIndexed { index, image ->

            Thread.sleep( 1000 ) //emulating network call.

            downloadImage(image, index)

        }

        notificationManager.cancel(notificationId)

        return Result.Success()

    }

    @SuppressLint ( "CheckResult" )

    private fun downloadImage(image: Image, index: Int) {

        val client = OkHttpClient()

        val request = Request.Builder()

            .url(image.url)

            .build()

        try {

            val response = client.newCall(request).execute()

            val bitmap = BitmapFactory.decodeStream(response.body()?.byteStream())

            ImageUtil.saveBitmap(mContext, bitmap, image.title).subscribe({ img ->

                displayNotification(ProgressUpdateEvent(image.title, 3 , index + 1 ))

                EventBus.getDefault().post(ImageDownloadedEvent(img, image.title, image.id))

            }, { error ->

                error.printStackTrace()

            })

        } catch (e: Exception) {

            e.printStackTrace()

        }

    }

    private val notificationId: Int = 500

    private val notificationChannel: String = "demo" 
    private fun displayNotification(prog: ProgressUpdateEvent) {

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

            val channel = NotificationChannel(

                notificationChannel,

                notificationChannel,

                NotificationManager.IMPORTANCE_DEFAULT

            )

            channel.enableVibration( false )

            notificationManager.createNotificationChannel(channel)

        }

        val notificationBuilder =

            NotificationCompat.Builder(applicationContext, notificationChannel)

        val remoteView = RemoteViews(applicationContext.packageName, R.layout.custom_notif)

        remoteView.setImageViewResource(R.id.iv_notif, R.drawable.eminem)

        remoteView.setTextViewText(R.id.tv_notif_progress, "${prog.message} (${prog.progress}/${prog.total} complete)" )

        remoteView.setTextViewText(R.id.tv_notif_title, "Downloading Images" )

        remoteView.setProgressBar(R.id.pb_notif, prog.total, prog.progress, false ) 
        notificationBuilder

            .setContent(remoteView)

            .setSmallIcon(R.drawable.eminem)

        notificationManager.notify(notificationId, notificationBuilder.build())

    }

    override fun onStopped() {

        super .onStopped()

        notificationManager.cancel(notificationId)

    }

    data class ProgressUpdateEvent(var message: String, var total: Int, var progress: Int)
}

我们正在发送来自员工的事件。 我们将在MainActivity类中捕获它并显示图像。

只需在onStart中初始化EventBus并在onStop中停止它即可。 最终的MainActivity.kt文件如下所示:

 package com.example.workmanagerdemo
 import android.annotation.SuppressLint
 import android.os.Bundle
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
 import androidx.work.*
 import com.squareup.picasso.Picasso
 import kotlinx.android.synthetic.main.activity_main.*
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import java.io.File
 MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() { 
    val jsonString: String = "[\n" +

            " {\n" +

            "   \"albumId\": 1,\n" +

            "   \"id\": 1,\n" +

            "   \"title\": \"Eminem\",\n" +

            "   \"url\": \" https://i.pinimg.com/originals/c4/14/4f/c4144fba258c2f0b4735180fe5d9a03b.jpg \",\n" +

            "   \"thumbnailUrl\": \" https://via.placeholder.com/150/92c952 \"\n" +

            " },\n" +

            " {\n" +

            "   \"albumId\": 1,\n" +

            "   \"id\": 2,\n" +

            "   \"title\": \"MEME\",\n" +

            "   \"url\": \" https://pics.me.me/eminems-emotions-suprised-sad-happy-curious-annoyed-excited-shocked-bored-13877943.png \",\n" +

            "   \"thumbnailUrl\": \" https://via.placeholder.com/150/771796 \"\n" +

            " },\n" +

            " {\n" +

            "   \"albumId\": 1,\n" +

            "   \"id\": 3,\n" +

            "   \"title\": \"Eminem News\",\n" +

            "   \"url\": \" https://www.sohh.com/wp-content/uploads/Eminem.jpg \",\n" +

            "   \"thumbnailUrl\": \" https://via.placeholder.com/150/24f355 \"\n" +

            " }]"

    @SuppressLint ( "CheckResult" )

    override fun onCreate(savedInstanceState: Bundle?) {

        super .onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

        btn_download.setOnClickListener {

            startWorker()

        }

    }

    private fun startWorker() {

        val data = Data.Builder()

            .putString( "images" , jsonString)

            .build()

        val constraints = Constraints.Builder()

            .setRequiredNetworkType(NetworkType.CONNECTED)

        val oneTimeRequest = OneTimeWorkRequest.Builder(ImageDownloadWorker:: class .java)

            .setInputData(data)

            .setConstraints(constraints.build())

            .addTag( "demo" )

            .build()

        Toast.makeText( this , "Starting worker" , Toast.LENGTH_SHORT).show() 
        WorkManager.getInstance( this )

            .enqueueUniqueWork( "AndroidVille" , ExistingWorkPolicy.KEEP, oneTimeRequest)

    }

    @Subscribe (threadMode = ThreadMode.MAIN)

    fun onEvent(imageDownloadedEvent: ImageDownloadedEvent) {

        val file = File( "${imageDownloadedEvent.path}/${imageDownloadedEvent.name}" )

        when (imageDownloadedEvent.id) {

            "1" -> Picasso.get().load(file).into(iv_1)

            "2" -> Picasso.get().load(file).into(iv_2)

            "3" -> Picasso.get().load(file).into(iv_3)

        }

    }

    override fun onStart() {

        super .onStart()

        EventBus.getDefault().register( this )

    }

    override fun onStop() {

        super .onStop()

        EventBus.getDefault().unregister( this )

    }
 }

这是最终的应用程序:

这将我们带到Android教程中工作管理器的结尾。 如果您对应用程序有任何疑问,请在下面的评论中告诉我,我们将竭诚为您服务。

您可以在github上找到此项目的存储库: https : //github.com/Ayusch/WorkManagerDemo

翻译自: https://www.javacodegeeks.com/2020/09/using-work-manager-in-android-with-example.html

接口文档示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值