Service 问题大盘点

qiang.zhang大约 7 分钟

Service 问题大盘点

  1. 什么时候选择服务,什么时候选择线程?

简单地说,服务是一种即使用户未与应用交互也可在后台运行的组件,因此,只有在需要服务时才应创建服务。

如果我们必须在主线程之外执行操作,但只在用户与我们的应用交互时执行此操作,则应创建新线程。例如,如果只是想在 Activity 运行的同时播放一些音乐,则可在 onCreate() 中创建线程,在 onStart() 中启动线程运行,然后在 onStop() 中停止线程。还可考虑使用 AsyncTask 或 HandlerThread,而非传统的 Thread 类。

如果确实要使用服务,则默认情况下,它仍会在应用的主线程中运行,因此,如果服务执行的是密集型或阻止性操作,则仍应在服务内创建新线程。

  1. IntentService是什么?

IntentService是Service的子类,是一个异步的、会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题。

IntentService 是一个特殊的 Service,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能使用 IntentService。 它封装了 HandlerThread 和 Handler,可用于执行后台耗时的任务,当任务全部执行完毕后自动停止。 它的优先级比普通线程要高,所以适合执行高优先级的后台任务。 (HandlerThread是继承了Thread,他的作用是不用每次创建线程,他内部有循环机制可以重复利用,不用的时候要quit或者quitSafely。)

  1. 说说 Activity、Intent 和 Service 是什么关系

他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是 Context 类的子类 ContextWrapper 的子类。Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间可以通过 Intent 传递数据,因此可以把 Intent 看作是通信使者。

  1. 如何保证Service不被杀死?(提高Service优先级)
  • 在AndroidManifest.xml配置文件设置android:priority 属性,和有序广播一样。

  • 在onStartCommand里面调用 startForeground()方法把Service提升为前台进程级别,然后再onDestroy里面要记得调用stopForeground()方法。

  • onStartCommand方法,手动返回START_STICKY。

  • 在onDestroy方法里发广播重启service。service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service。(第三方应用或是在setting里-应用-强制停止时,APP进程就直接被干掉了,onDestroy方法都进不来,所以无法保证会执行)

  • 监听系统广播判断Service状态。通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活。

  1. Service 和 BroadcastReceiver 共同点

都是运行在主线程当中,都不能做长时间的耗时操作。

  1. Service 里面可以弹出toast吗

可以的,Service不仅可以弹Toast还能弹出对话框,第一,Service是运行在主线程当中;第二,弹Toast有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类;因此在 Service 里面弹吐司是完全可以的。

  1. 是否能在Service进行耗时操作?如果非要可以怎么做?

Service默认运行在主线程中,所以不能在Service里执行耗时操作,除非手动打开一个子线程,否则有可能出现主线程被阻塞(ANR)的情况。(开启子线程的方法有:继承、实现、匿名类) ,可以使用IntentService来代替,因为它是一个异步的、会自动停止的Service服务。

  1. 一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?

当对一个服务既调用 startService() 方法,又调用了bindService()方法,根据Android系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况要同时调用是stopService()和unbindService方法,onDestroy才会执行。

  1. 前台服务是什么?和普通服务的不同?如何去开启一个前台服务?

前台服务和普通服务最大的区别是:前者会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。使用前台服务或者为了防止服务被回收掉,比如听歌,或者由于特殊的需求,比如实时天气状况。

实现前台服务:

Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent =
        PendingIntent.getActivity(this, 0, notificationIntent, 0);

Notification notification =
          new Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
    .setContentTitle(getText(R.string.notification_title))
    .setContentText(getText(R.string.notification_message))
    .setSmallIcon(R.drawable.icon)
    .setContentIntent(pendingIntent)
    .setTicker(getText(R.string.ticker_text))
    .build();

startForeground(ONGOING_NOTIFICATION_ID, notification);

  1. AlarmManager能实现定时的原理?

通过调用AlarmManager的 set() 方法就可以设置一个定时任务,并提供三个参数(工作类型,定时任务触发的时间,PendingIntent对象)。其中第三个PendingIntent对象是关键,一般会调用它的 getBroadcast() 方法来获取一个能够执行广播的PendingIntent。这样当定时任务被触发的时候,广播接收器的onReceive()方法就可以得到执行。即通过服务和广播的循环触发实现定时服务。

  1. Service 和 Thread 的区别

定义:

Thread 是程序执行的最小单元,它是分配CPU的最小单位。可以执行异步操作,是相对独立的。 Service 是 Android 的一种特殊机制,是运行在主线程当中的,是依托于所在的主线程。是由系统进程托管,也是一种轻量级IPC通信方式(Activity 和 Service 绑定,然后数据通信,并处于不同进程。) 关系:Service 和 Thread 之间并没有什么关联,Service 翻译成中文是服务,同时服务可以理解为后台。Thread 是开启子线程执行耗时操作,而 Service 是在主线程中执行,但总被认为可以在后台处理耗时任务,容易混淆了两者之间的概念。

实际开发中:

在Android系统当中,线程一般指的是工作线程,主线程主要负责UI绘制,而Service 就是运行在主线程当中的。

应用场景:

当需要耗时的操作,比如网络请求,图片加载等等都应该使用工作线程。 当需要在后台播放音乐、开启定位、数据统计等等应该使用Service。

区分:

  • 不要把后台和子线程联系在一起;
  • 服务和后台是不同的概念;
  • Android的后台是指它的运行不依赖与UI线程,即使程序被销毁了、程序被关闭了,服务进程仍然在后台进行计算、统计等等。
  • 如果在 Service 执行耗时,也需要创建子线程,然后去做耗时逻辑。
  • Service是为了弥补 Activity 被销毁之后,无法获取之前所创建的子线程实例,并对后台进行控制的情况而产生的。
  1. Service 的 onStartCommand 方法有几种返回值?各代表什么意思? 有四种返回值,不同值代表的意思如下:
  • START_STICKY:如果 service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。随 后系统会尝试重新创建 service,由于服务状态为开始状态,所以创建服务后一定会调用 onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到 service,那么参数 Intent 将为 null。

  • START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。

  • START_REDELIVER_INTENT:重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。

  • START_STICKY_COMPATIBILITY: START_STICKY 的兼容版本,但不保证服务被 kill 后一定能重启。

  1. 一般在什么情况下会使用Service?

当需要长期在后台进行的工作我们需要将其放在Service中去做,比如音乐播放、下载、上传大文件、定时关闭应用等功能。这样做的原因是如果放在Activity当中去执行的话,当Activity销毁后,那这些功能也就停止了,这显然是不符合设计要求的,所以要将他们放在Service中去执行。

Loading...