Memigrasikan layanan latar depan ke tugas transfer data yang dimulai pengguna

Android 14 menerapkan aturan ketat tentang kapan aplikasi diizinkan untuk menggunakan layanan latar depan.

Di Android 14, kami juga memperkenalkan API baru untuk menentukan bahwa tugas harus berupa tugas transfer data yang dimulai pengguna. API ini berguna untuk kasus penggunaan yang memerlukan transfer data berdurasi lebih lama dan dimulai oleh pengguna, seperti mendownload file dari server jarak jauh. Jenis tugas ini harus menggunakan tugas transfer data yang dimulai pengguna.

Tugas transfer data yang dimulai pengguna dimulai oleh pengguna. Tugas ini memerlukan notifikasi, segera dimulai, dan mungkin dapat berjalan untuk jangka waktu lama sesuai kondisi sistem. Anda dapat menjalankan beberapa tugas transfer data yang dimulai oleh pengguna secara serentak.

Tugas yang dimulai oleh pengguna harus dijadwalkan saat aplikasi terlihat oleh pengguna (atau dalam salah satu kondisi yang diizinkan). Setelah semua batasan terpenuhi, tugas yang dimulai pengguna dapat dijalankan oleh OS, tunduk pada pembatasan kesehatan sistem. Sistem juga dapat menggunakan estimasi ukuran payload yang disediakan untuk menentukan berapa lama tugas akan dijalankan.

Izin untuk tugas transfer data yang dimulai pengguna

Tugas transfer data yang dimulai pengguna memerlukan izin baru untuk dijalankan: RUN_USER_INITIATED_JOBS. Sistem memberikan izin ini secara otomatis. Sistem akan menampilkan SecurityException jika Anda tidak mendeklarasikan izin dalam manifes aplikasi.

Proses untuk menjadwalkan tugas transfer data yang dimulai pengguna

如需运行用户发起的作业,请执行以下操作:

  1. 如果这是您第一次使用 JobScheduler 声明 API,请在清单中声明 JobService 和相关权限。此外,还要为数据传输定义 JobService 的具体子类:

    <service android:name="com.example.app.CustomTransferService"
            android:permission="android.permission.BIND_JOB_SERVICE"
            android:exported="false">
            ...
    </service>
    
    class CustomTransferService : JobService() {
      ...
    }
    
  2. 在清单中声明 RUN_USER_INITIATED_JOBS 权限:

    <manifest ...>
        <uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />
        <application ...>
            ...
        </application>
    </manifest>
    
  3. 构建 JobInfo 对象时,调用新的 setUserInitiated() 方法。我们还建议您在创建作业时通过调用 setEstimatedNetworkBytes() 提供载荷大小估算值:

    val networkRequestBuilder = NetworkRequest.Builder()
            .addCapability(NET_CAPABILITY_INTERNET)
            .addCapability(NET_CAPABILITY_NOT_METERED)
            // Add or remove capabilities based on your requirements
            .build()
    
    val jobInfo = JobInfo.Builder()
            // ...
            .setUserInitiated(true)
            .setRequiredNetwork(networkRequestBuilder.build())
            .setEstimatedNetworkBytes(1024 * 1024 * 1024)
            // ...
            .build()
    
  4. 在应用可见或在允许的条件列表中,作业应在转移开始前调度:

    val jobScheduler: JobScheduler =
        context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
    jobScheduler.schedule(jobInfo)
    
  5. 执行作业时,请确保对 JobService 对象调用 setNotification()。该值用于在任务管理器和状态栏通知区域中告知用户作业正在运行:

    class CustomTransferService : JobService() {
      override fun onStartJob(params: JobParameters?): Boolean {
          val notification = Notification.Builder(applicationContext, NOTIFICATION_CHANNEL_ID)
                  .setContentTitle("My user-initiated data transfer job")
                  .setSmallIcon(android.R.mipmap.myicon)
                  .setContentText("Job is running")
                  .build()
    
          setNotification(params, notification.id, notification,
                  JobService.JOB_END_NOTIFICATION_POLICY_DETACH)
          // Do the job execution.
      }
    }
    
  6. 定期更新通知,让用户了解作业的状态和进度。如果您在安排作业之前无法确定传输大小,或者需要更新估算的传输大小,请在已知传输大小后使用新的 API updateEstimatedNetworkBytes() 更新传输大小。

  7. 执行完成后,调用 jobFinished() 以向系统表明作业已完成,或者应重新调度作业。

Tugas transfer data yang dimulai pengguna dapat dihentikan

Pengguna dan sistem dapat menghentikan tugas transfer yang dimulai pengguna.

Oleh pengguna, dari Pengelola Tugas

Pengguna dapat menghentikan tugas transfer data yang dimulai pengguna dan muncul di Pengelola Tugas.

Saat pengguna menekan Stop, sistem akan melakukan hal berikut:

  • Menghentikan proses aplikasi Anda dengan segera, termasuk semua tugas lain atau layanan latar depan yang sedang berjalan.
  • Tidak memanggil onStopJob() untuk tugas yang sedang berjalan.
  • Mencegah tugas yang terlihat oleh pengguna agar tidak dijadwalkan ulang.

Oleh karena itu, sebaiknya berikan kontrol dalam notifikasi yang diposting untuk tugas itu guna memungkinkan penghentian dan penjadwalan ulang tugas dengan baik.

Perlu diperhatikan bahwa, dalam keadaan khusus, tombol Stop tidak akan muncul di samping tugas di Pengelola Tugas, atau tugas tidak ditampilkan sama sekali di Pengelola Tugas.

Oleh sistem

与常规作业不同,用户发起的数据传输作业不受应用待机模式存储分区配额的影响。但是,如果出现以下任一情况,系统仍会停止作业:

  • 不再满足开发者定义的约束条件。
  • 系统确定该作业的运行时间超出了完成数据传输任务所需的时间。
  • 系统需要优先考虑系统运行状况,并因发热程度上升而停止作业。
  • 应用进程因设备内存不足而被终止。

系统停止作业(并非因为内存不足)时,系统会调用 onStopJob(),系统会在系统认为最佳的时间重试作业。检查您的应用是否可以保留数据传输状态(即使未调用 onStopJob()),并且您的应用可以在再次调用 onStartJob() 时恢复此状态。

Kondisi yang diizinkan untuk menjadwalkan tugas transfer data yang dimulai pengguna

只有当应用处于可见窗口中或满足特定条件时,应用才能启动用户发起的数据传输作业。为确定何时可以安排用户发起的数据传输作业,系统会采用允许应用在特殊情况下从后台启动 activity 的一组相同条件。值得注意的是,这组条件与后台启动的前台服务限制的豁免集不同。

上述说明的例外情况包括:

  • 如果应用可以从后台启动 activity,则也可以从后台启动用户发起的数据传输作业。
  • 如果应用在最近用过屏幕上现有任务的返回堆栈中有 activity,单靠这一点并不允许运行用户发起的数据传输作业。

如果作业安排在允许的条件列表中未列出的其他时间,则作业将失败并返回 RESULT_FAILURE 错误代码。

Batasan yang diizinkan untuk tugas transfer data yang dimulai pengguna

Untuk mendukung tugas agar berjalan pada titik yang optimal, Android menawarkan kemampuan untuk menetapkan batasan bagi setiap jenis tugas. Batasan ini sudah tersedia mulai Android 13.

Catatan: Tabel berikut hanya membandingkan batasan yang bervariasi antara setiap jenis tugas. Lihat halaman developer JobScheduler atau batasan kerja untuk semua batasan.

Tabel berikut menunjukkan berbagai jenis tugas yang mendukung batasan tugas tertentu, serta kumpulan batasan tugas yang didukung WorkManager. Gunakan kotak penelusuran sebelum tabel untuk memfilter tabel berdasarkan nama metode batasan tugas.

Berikut ini batasan yang diizinkan dengan tugas transfer data yang dimulai pengguna:

  • setBackoffCriteria(JobInfo.BACKOFF_POLICY_EXPONENTIAL)
  • setClipData()
  • setEstimatedNetworkBytes()
  • setMinimumNetworkChunkBytes()
  • setPersisted()
  • setNamespace()
  • setRequiredNetwork()
  • setRequiredNetworkType()
  • setRequiresBatteryNotLow()
  • setRequiresCharging()
  • setRequiresStorageNotLow()

Pengujian

Daftar berikut menunjukkan beberapa langkah untuk menguji tugas aplikasi secara manual:

  • Untuk mendapatkan ID tugas, dapatkan nilai yang ditentukan saat tugas di-build.
  • Untuk langsung menjalankan tugas, atau untuk mencoba kembali tugas yang dihentikan, jalankan perintah berikut di jendela terminal:

    adb shell cmd jobscheduler run -f APP_PACKAGE_NAME JOB_ID
    
  • Untuk menyimulasikan penghentian paksa sebuah tugas oleh sistem (karena kondisi sistem atau kondisi kehabisan kuota), jalankan perintah berikut di jendela terminal:

    adb shell cmd jobscheduler timeout TEST_APP_PACKAGE TEST_JOB_ID