Service
--------------首先要创建服务,必须创建 Service 的子类,同时重写一些回调方法;
package com.example.demoservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service {
private MBinder mBinder = new MBinder();
class MBinder extends Binder {
public void getService() {
Toast.makeText(MyService.this, R.string.get_service_success, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(MyService.this, R.string.service_create, Toast.LENGTH_SHORT).show();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(MyService.this, R.string.service_start_command, Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(MyService.this, R.string.service_destroy, Toast.LENGTH_SHORT).show();
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
onBind():当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须返回一个IBinder 接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
onCreate():首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次。
onStartCommand():当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)如果希望服务一旦启动就立刻执行某个操作,可以讲逻辑写在这里。
onDestroy():当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。销毁服务时,应该在onDestroy()方法中去回收那些不再使用的资源。
------------------如何让Activity与Service通信?实现ServiceConnection注意点?
Activity是通过实现 ServiceConnection 接口来与服务建立连接的,它包含以下两个方法:
onServiceConnected(ComponentName name, IBinder service):服务绑定成功后,会回调该方法;若服务异常中断后重启,也会重新调用该方法;
onServiceDisconnected(ComponentName name) :服务异常解绑\终止后调用该方法;注意,unbindService()不会调用该方法;
服务是通过实现 IBinder onBind(Intent intent) 方法来转换为 onServiceConnected() 方法所需要的 IBinder 型的 service 参数的。
-------------创建 ServiceConnection 实例:
/**
* 将IBinder类的对象iBinder向下转型成MyService.MBinder类的对象binder,形成一个connection
*/
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
binder = (MyService.MBinder) iBinder;
Toast.makeText(MainActivity.this, R.string.service_connect_success, Toast.LENGTH_SHORT).show();
binder.getService();
mServiceConnect = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Toast.makeText(MainActivity.this, R.string.service_disconnect, Toast.LENGTH_SHORT).show();
mServiceConnect = false;
}
};
----------------绑定服务:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
1. service是什么?
service是一个服务,可以在后台执行长时间运行操作而没有用户界面的应用组件,可以用activity和broadcast启动,service只要启动就会在后台一直运行,哪怕启动他的activity已经被销毁也不会受影响,当然也可以绑定activity可以与ACitivy进行通讯,service是运行在主线程中,不能做耗时操作
2. Service的生命周期?bindService和startService?
只是用startService()启动服务:onCreate() -> onStartCommand() -> onDestory(stopService()/stopSelf)
只是用bindService()绑定服务(获取一个服务持久连接):onCreate() -> onBind() -> onUnBind() ->onDestory
即调用startService()启动服务又调用了bindService()绑定服务,必须同时调用stopService()和unbindService():onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory
3. Service有哪几种启动方式?
startService:
如果一个Service被某个Activity 使用 startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,但它依旧运行于main线程。如果这个Service被startService方法多次启动,那么onCreate方法只会调用一次,onStartCommand将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例。该Service将会一直在后台运行,即使启动它的Activity已经退出,它直到某个activity调用stopService,或自身调用的stopSelf方法才会结束服务。当然如果系统资源不足,android系统也可能结束服务。
bindService():
如果一个Service被某个Activity 调用 bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStartCommand()方法不会被调用。当连接建立之后,Service将会一直运行,除非调用unbindService 方法断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统才会自动停止Service,对应onDestroy将被调用。(unbindService 不会调用onDestory)
还有一中复杂用法,就是同时使用startService和bindService方式启动服务。如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须由外界的activity调用 stopService 或 Service自身调用stopSelf 来停止服务。
4. 多次启动Service,一次stop,Service是否还存在?多次绑定Service,一次unbind,Service是否还存在?
StartService是一对一的,多个Activity多次启动或单个Activity单次Service,一次stop,Service不存在;
bindService是多对一的,多个Activity多次绑定Service,一次unbind,Service存在
6. IntentService
Service中的代码都是默认运行在主线程中,为了避免ANR,应该在Service的具体执行方法中开启一个子线程。为了可以简单地创建一个异步、会自动停止的Service,Android专门提供了一个IntentService类。
public class MyIntentService extends IntentService {
public MyIntentService(){
//调用父类的有参构造函数
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//在这里处理耗时操作,当执行完成后会自动停止Service
}
}
IntendService使用场景:
IntentService相比父类Service而言,最大特点是其回调函数onHandleIntent中可以直接进行耗时操作,不必再开线程。其原理是IntentService的成员变量 Handler在初始化时已属于工作线程,之后handleMessage,包括onHandleIntent等函数都运行在工作线程中。
如果对IntentService的了解仅限于此,会有种IntentService很鸡肋的观点,因为在Service中开线程进行耗时操作也不麻烦。我当初也是这个观点,所以很少用IntentService。
但是IntentService还有一个特点,就是多次调用onHandleIntent函数(也就是有多个耗时任务要执行),多个耗时任务会按顺序依次执行。原理是其内置的Handler关联了任务队列,Handler通过looper取任务执行是顺序执行的。
这个特点就能解决多个耗时任务需要顺序依次执行的问题。而如果仅用service,开多个线程去执行耗时操作,就很难管理。
例如在之前做的app中,有一个需求是下载某段时间用户保存的图片,下载完成后显示在imageView中;一般需要下载的图片有很多,每下一个图片就是一个线程,下载完后立即显示出来,所以肯定希望下载是按顺序依次下载,这样用户体验就比较好。当时的处理方式欠妥,直接开多个线程去下载,在前一个图片下载完成之前,其他线程必须等待;这样虽然也可以实现功能,但效率上不高,甚至可能出现ANR(具体代码逻辑是,如果后面的线程获得了cpu,而前面的图片还没下完,则等待;假设前一张图片没下完,而后面的线程一直获得cpu,就有问题)。
如果这个场景使用IntentService就非常方便,每个耗时任务都按顺序依次执行,不必担心出现逻辑上或性能上的问题,也是IntentService的价值所在。
总结:Android中很多类都是为某些常用场景所设计,例如本文中的IntentService以及之前写过的handlerThread等类,平时多积累,在以后遇到一些棘手问题时才能迎刃而解。
7. 哪些是前台服务?哪些是后台服务?
Service几乎都是在后台运行的,一直以来它都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service.
8. 如何提高Service的优先级?
--------添加android:persistent=“true”
--------设置onStartCommand()的返回值
--------startForeground()提高service的进程等级
9. Service的onStartCommand方法有哪几种返回值?各代表什么意思?
START_STICKY:kill后会被重启,但是重启后调用onStarfCommand()传进来的Intent参数为null,说明被kill的时候没有保存Intent;
START_STICKY_COMPATIBILITY:START_STICKY的兼容版,但是不能保证onStartCommand()方法被调用,如果应用程序的targetSdkVersion 小于 2.0版本,就会返回该值,否则返回START_STICKY,同时再次启动时只会调用onCreate(),不保证能调用onStartCommand()方法
START_NOT_STICKY:kill之后不会被重启;
START_REDELIVER_INTENT:kill后会被重启,同时重启调用onStartCommand()时再次传入保存的Intent。
10. Activity调用Service中的方法有哪几种?
Binder对象,aidl, Messenger