当前位置: 首页 > news >正文

从service 到 JobIntentService 和 WorkManager

目录

  • service
      • 1. Service 的概念
      • 2. Service 的生命周期
      • 3. Service 的启动方式
      • 4. Service 的使用场景
      • 5. 实现一个简单的 Service
        • 步骤 1:定义 Service
        • 代码说明
        • 步骤 2:在 AndroidManifest.xml 中注册 Service
        • 步骤 3:从 Activity 启动和停止 Service
        • 步骤 4:布局文件(activity_main.xml)
      • 2. 使用 startForeground() 创建前台服务
        • 示例代码:
        • 代码说明:
  • JobIntentService
      • 3. 使用 JobIntentService
          • 特点
          • 使用场景
        • 示例代码:
        • 代码说明:
  • WorkManager
      • 4. 使用 WorkManager
          • 特点
          • 使用场景
        • 示例代码:
        • 代码说明:
      • 总结


Android 系统对后台服务的限制越来越严格,特别是从 Android 8(API 级别 26)开始,后台服务的使用受到限制。如果需要在后台持续运行,可以考虑使用 JobIntentService 或 WorkManager。

service

1. Service 的概念

Service 是 Android 四大组件之一,它是一个用于在后台执行长时间运行操作的组件,没有用户界面。Service 的主要用途包括:

  • 执行后台任务,如下载文件、播放音乐、同步数据等。
  • 提供后台服务,如通知推送、定时任务等。
  • 与其他组件(如 ActivityBroadcastReceiver)进行交互。

2. Service 的生命周期

Service 的生命周期主要由以下几个方法控制:

  • onCreate():当 Service 被创建时调用。如果 Service 已经运行,则不会再次调用。
  • onStartCommand():当通过 startService() 启动 Service 时调用。每次调用 startService() 都会触发此方法。
  • onBind():当通过 bindService() 绑定 Service 时调用。如果 Service 已经绑定,则不会再次调用。
  • onUnbind():当所有绑定的客户端都解绑时调用。
  • onDestroy():当 Service 被销毁时调用。

3. Service 的启动方式

Service 可以通过两种方式启动:

  • 显式启动:通过 startService() 方法启动。这种方式启动的 Service 会一直运行,直到调用 stopService()stopSelf()
  • 绑定启动:通过 bindService() 方法启动。这种方式启动的 Service 会与绑定的组件(如 Activity)的生命周期相关联。当所有绑定的组件都解绑时,Service 会被销毁。

如果需要 Service 在后台持续运行,建议使用 startForeground() 方法将其置于前台。

4. Service 的使用场景

  • 后台任务:如下载文件、同步数据等。
  • 播放音乐:在后台播放音乐,即使用户离开了应用。
  • 定时任务:如定时推送通知。
  • 与后台服务交互:如与服务器进行通信。

5. 实现一个简单的 Service

接下来,通过一个简单的示例来展示如何实现一个 Service。这个 Service 将在后台执行一个简单的计时任务,并在日志中打印计时信息。

步骤 1:定义 Service
public class MyService extends Service {private static final String TAG = "MyService";private boolean isRunning = false;private int count = 0;@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "Service created");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "Service started");isRunning = true;new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {try {Thread.sleep(1000);count++;Log.d(TAG, "Count: " + count);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();return START_STICKY; // 如果系统杀死 Service,系统会重新启动它}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "Service destroyed");isRunning = false;}@Overridepublic IBinder onBind(Intent intent) {// 返回一个 IBinder 对象,用于绑定服务return null;}
}
代码说明
  1. onCreate():当 Service 被创建时调用。
  2. onStartCommand():当通过 startService() 启动 Service 时调用。这里启动了一个后台线程,每秒打印一次计时信息。
  3. onDestroy():当 Service 被销毁时调用。这里将 isRunning 设置为 false,停止后台线程。
  4. onBind():当通过 bindService() 绑定 Service 时调用。这里返回 null,因为我们不支持绑定。
步骤 2:在 AndroidManifest.xml 中注册 Service
<application...><serviceandroid:name=".MyService"android:enabled="true"android:exported="false" />
</application>
步骤 3:从 Activity 启动和停止 Service
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 启动 ServiceButton startButton = findViewById(R.id.startButton);startButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent startIntent = new Intent(MainActivity.this, MyService.class);startService(startIntent);}});// 停止 ServiceButton stopButton = findViewById(R.id.stopButton);stopButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent stopIntent = new Intent(MainActivity.this, MyService.class);stopService(stopIntent);}});}
}
步骤 4:布局文件(activity_main.xml)
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"><Buttonandroid:id="@+id/startButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Start Service" /><Buttonandroid:id="@+id/stopButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Stop Service" />
</LinearLayout>

通过上述代码,实现了一个简单的 Service,它在后台运行并每秒打印一次计时信息。Service 的生命周期方法(如 onCreate()onStartCommand()onDestroy())用于控制服务的启动和停止。还通过 startService()stopService() 方法从 Activity 中启动和停止服务。

2. 使用 startForeground() 创建前台服务

前台服务会显示一个通知,用户可以清楚地看到服务正在运行。前台服务不会被系统轻易杀死。

示例代码:
public class ForegroundService extends Service {private static final int NOTIFICATION_ID = 1;private static final String CHANNEL_ID = "ForegroundServiceChannel";@Overridepublic void onCreate() {super.onCreate();// 创建通知渠道(Android 8 及以上版本需要)createNotificationChannel();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 创建通知Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("Foreground Service").setContentText("Service is running").setSmallIcon(R.drawable.ic_notification).build();// 将服务置于前台startForeground(NOTIFICATION_ID, notification);// 模拟后台任务new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);Log.d("ForegroundService", "Running: " + i);} catch (InterruptedException e) {e.printStackTrace();}}// 任务完成后停止服务stopSelf();}}).start();return START_NOT_STICKY;}@Overridepublic void onDestroy() {super.onDestroy();// 停止前台服务stopForeground(true);}@Overridepublic IBinder onBind(Intent intent) {return null;}// 创建通知渠道private void createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID,"Foreground Service Channel",NotificationManager.IMPORTANCE_DEFAULT);NotificationManager manager = getSystemService(NotificationManager.class);manager.createNotificationChannel(serviceChannel);}}
}
代码说明:
  1. createNotificationChannel():创建通知渠道(Android 8 及以上版本需要)。
  2. startForeground():将服务置于前台,并显示通知。
  3. NotificationCompat.Builder:构建通知内容。
  4. new Thread():在后台线程中执行任务。
  5. stopSelf():任务完成后停止服务。
  6. stopForeground():在服务销毁时停止前台服务。

JobIntentService

3. 使用 JobIntentService

JobIntentService 是一个兼容类,用于在后台执行任务。它在 Android 8 及以上版本中会使用 JobScheduler,在旧版本中则会回退到 IntentService

特点
  • 兼容性:兼容从 Android 4.0 到最新版本。
  • 后台任务处理:适用于简单的后台任务,如数据同步、文件下载等。
  • 自动管理 Wake Locks:在 Android Oreo 及以上版本中,JobIntentService 会自动管理 Wake Locks。
  • 任务调度:在 Android Oreo 及以上版本中,任务通过 JobScheduler 调度;在旧版本中,任务通过 startService() 执行。
使用场景
  • 执行耗时操作,如下载文件、上传数据等。
  • 需要兼容旧版本系统的后台任务。
示例代码:
public class MyJobIntentService extends JobIntentService {// 定义一个服务IDstatic final int JOB_ID = 1000;// 启动服务的静态方法public static void enqueueWork(Context context, Intent work) {enqueueWork(context, MyJobIntentService.class, JOB_ID, work);}@Overrideprotected void onHandleWork(@NonNull Intent intent) {// 模拟后台任务for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);Log.d("MyJobIntentService", "Running: " + i);} catch (InterruptedException e) {e.printStackTrace();}}}
}
代码说明:
  1. enqueueWork():静态方法用于启动服务。
  2. onHandleWork():在后台线程中执行任务。
  3. enqueueWork():将任务加入队列,JobIntentService 会根据系统版本选择合适的后台执行方式。

WorkManager

4. 使用 WorkManager

WorkManager 是 Android 官方推荐的后台任务调度框架,适用于需要灵活调度的任务,例如周期性任务或延迟任务。它支持一次性任务、周期性任务,并且可以根据设备的条件(如网络状态、电池电量等)执行任务。

特点
  • 灵活的任务调度:支持一次性任务、周期性任务。
  • 条件约束:可以根据网络状态、电池电量等条件执行任务。
  • 兼容性:兼容从 Android 4.0 到最新版本。
  • 可靠性:即使应用退出或设备重启,任务也能继续执行。
使用场景
  • 定期同步数据。
  • 在后台处理耗时任务。
  • 需要根据设备条件执行的任务。
示例代码:
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建一个一次性工作请求OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class).setConstraints(new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()).build();// 将工作请求加入队列WorkManager.getInstance(this).enqueue(workRequest);}
}public class MyWorker extends Worker {public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {super(context, workerParams);}@NonNull@Overridepublic Result doWork() {// 模拟后台任务for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);Log.d("MyWorker", "Running: " + i);} catch (InterruptedException e) {e.printStackTrace();}}// 返回任务执行结果return Result.success();}
}
代码说明:
  1. OneTimeWorkRequest:创建一个一次性任务请求。
  2. Constraints:设置任务执行的约束条件,例如需要网络连接。
  3. WorkManager.getInstance().enqueue():将任务加入队列。
  4. MyWorker:继承自 Worker,在 doWork() 方法中实现后台任务逻辑。
  5. Result.success():返回任务执行结果。

总结

  • startForeground():适用于需要持续运行且用户需要知晓的任务。
  • JobIntentService:适用于简单的后台任务,兼容旧版本系统。
  • WorkManager:适用于需要灵活调度的任务,如周期性任务或延迟任务。

相关文章:

  • 香港电讯荣膺“卓越互联网接入服务提供商”奖项,赋能中国汽车产业数字化转型
  • Linux环境准备(安装VirtualBox和Ubuntu,安装MySQL,MySQL启动、重启和停止)
  • KUKA机器人不同的安装方式的设置
  • LeetCode面试经典 150 题(Java题解)
  • C++ vector 核心功能解析与实现
  • TOGAF 敏捷冲刺:15 天 Scrum 冲刺实践
  • 新能源汽车零部件功率级测试方案搭建研究
  • STM32F103_HAL库+寄存器学习笔记19 - CAN发送中断+CAN接收中断+接收所有CAN报文+ringbuffer数据结构
  • 1.Vue3 - 创建Vue3工程
  • LeetCode 热题100题解(Java版本)
  • Anaconda Prompt 切换工作路径的方法
  • mac 本地 docker 部署 nacos
  • 多路由器通过RIP动态路由实现通讯(单臂路由)
  • 使用谷歌浏览器自带功能将网页转换为PDF文件
  • liunx中常用操作
  • 树莓派4b 连接USB无线网卡
  • Spark_SQL
  • 基于亚马逊云科技 Amazon Bedrock Tool Use 实现 Generative UI
  • 人工智能在运动医学中的最新应用方向探析
  • 安全协议分析概述
  • 江苏一季度实现地区生产总值3.3万亿元,同比增长5.9%
  • 徐之凯评《突如其来的勇气》|早熟的抵抗
  • 陈杨梅:为爸爸寻我19年没有放弃而感动,回家既紧张又期待
  • 德国男中音马蒂亚斯·格内:古典音乐的未来在亚洲
  • 美国多地举行抗议活动,特朗普经济政策支持率创新低
  • 美国海关新规致跨境包裹延误,DHL暂停超800美元对美个人货运