深入理解Android-清晰的理解Service

1、什么是Service
2、Service的生命周期
3、Service的工作过程
4、Service的start和bind状态有什么区别?
5、同一个Service,先startService,然后再bindService,如何把它停止掉?
6、你有注意到Service的onStartCommand方法的返回值吗?不同返回值有什么区别?
7、Service的生命周期方法onCreate、onStart、onBind等运行在哪个线程?

1.什么是service?

服务是一种应用程序组件,表示应用程序希望在不与用户交互的情况下执行长时间运行的操作,或者为其他应用程序提供的功能。每个服务类必须在其包的AndroidManifest.xml中具有相应的<service>声明。服务可以使用Context.startService()和Context.bindService()来启动。 请注意,与其他应用程序对象一样,服务在主机进程的主线程中运行。这意味着,如果你的服务要做任何CPU密集型(如MP3播放)或阻塞(如网络)操作,它应该产生自己的线程来完成这项工作。有关这方面的更多信息可以在“进程和线程”中找到。 IntentService类可作为Service的标准实现提供,它具有自己的线程,用于调度要完成的工作。

2.Service 的生命周期

Service有两种启动方式:

调用Context.startService(),那么系统将检索服务(如果需要,创建它并调用它的onCreate()方法),然后使用客户端提供的参数调用它的onStartCommand(Intent,int,int)方法。此服务将继续运行,直到调用Context.stopService()或stopSelf()。请注意,对Context.startService()的多次调用不会嵌套(尽管它们会导致对onStartCommand())进行多次相应调用),因此无论启动多少次,服务都会停止一次Context.stopService()或stopSelf () ;然而,服务可以使用他们的stopSelf(int)方法来确保服务不会停止,直到处理完启动的意图为止。对于已启动的服务,根据从onStartCommand()返回的值,他们可以决定运行两个额外的主要操作模式:START_STICKY用于根据需要显式启动和停止的服务,而使用START_NOT_STICKY或START_REDELIVER_INTENT对于在处理发送给它们的任何命令时应该只保持运行的服务。


调用 Context.bindService()来获得到服务的持久连接。如果服务尚未运行(同时调用onCreate()), 则同样会创建服务,但不会调用onStartCommand()。客户端将收到服务从其onBind(Intent)方法返回的IBinder对象,从而允许客户端将该服务调用回该服务。只要建立连接(无论客户是否保留对服务的IBinder的引用),该服务就会继续运行。返回的IBinder通常是用于一个复杂的接口,已经被写入aidl。
服务既可以启动,也可以绑定连接。在这种情况下,只要系统启动,或者存在与Context.BIND_AUTO_CREATE标志的一个或多个连接,系统就会继续运行该服务。一旦这些情况都不成立,就会调用服务的onDestroy()方法,并且服务被有效终止。从onDestroy()返回后,所有清理(停止线程,取消注册接收者)应该完成。


3.Service的工作过程

Service分为两种工作状态:一种是启动状态,主要用于执行后台计算;另一种是绑定状态,主要用于其他组件和service的交互。service的两种状态是可以共存的,那么Service既可以处于启动状态也可以处于绑定状态。

启动状态:

1 Intent intent = new Intent(this, MyService.class);
2 startService(intent);
1 Intent intent = new Intent(this, MyService.class);
2 
3 bindService(intent,conn,BIND_AUTO_CREATE);

service的启动过程

1.startService(intent);
我们看一下 service的源码 :package android.app.Service;

public abstract class Service extends ContextWrapper implements ComponentCallbacks2
Service 继承了ContextWrapper ,service的启动过程是从ContextWrapper 的startService开始
1  @Override
2     public ComponentName startService(Intent service) {
3         return mBase.startService(service);
4     }

通过mBase,调用startService

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

而Context类是个abstract

public abstract class Context
Activity被创建时会通过attach方法将一个ContextImpl对象关联起来 ,ContextImpl 实现了Context,mBase 的类型就是ContextImpl ,ContextWrapper 大部分操作都是通过mBase 完成的,这是一种典型的桥接模式。
startService 是通过Context调用的,那我们看下ContextImpl 是如何实现startService 的。

 1  @Override
 2     public ComponentName startService(Intent service) {
 3         warnIfCallingFromSystemProcess();
 4         return startServiceCommon(service, mUser);
 5     }
 6 
 7  private ComponentName startServiceCommon(Intent service, UserHandle user) {
 8         try {
 9             validateServiceIntent(service);
10             service.prepareToLeaveProcess(this);
11             // 开启服务  ActivityManagerNative.getDefault() 其实就是  ActivityManagerService(AMS)
12             ComponentName cn = ActivityManagerNative.getDefault().startService(
13                 mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
14                             getContentResolver()), getOpPackageName(), user.getIdentifier());
15             if (cn != null) {
16                 if (cn.getPackageName().equals("!")) {
17                     throw new SecurityException(
18                             "Not allowed to start service " + service
19                             + " without permission " + cn.getClassName());
20                 } else if (cn.getPackageName().equals("!!")) {
21                     throw new SecurityException(
22                             "Unable to start service " + service
23                             + ": " + cn.getClassName());
24                 }
25             }
26             return cn;
27         } catch (RemoteException e) {
28             throw e.rethrowFromSystemServer();
29         }
30     }

简单说一下 ActivityManagerNative

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
    /**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }

    /**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        return gDefault.get();
    }
}

 private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

public final class ActivityManagerService extends ActivityManagerNative
ActivityManagerService 是继承ActivityManagerNative的 AMS启动服务是一个远程调用过程,更具体的实现过程大家可以看源码,这里就不在长篇幅的写源码的启动过程了。
2.bindService 的绑定过程同样在ContextImpl 中,大家可自行翻阅理解。

4.Service的start和bind状态有什么区别?

start启动的service,不依赖组件,有独立的生命周期多次调用service不会嵌套,尽管会对onStartCommand()多次调用,因此无论启动多少次,服务都会停止一次Context.stopService()或stopSelf ()(IntentService会自动调用一次onStopSelf).然而,服务可以使用他们的stopSelf(int)方法来确保服务不会停止,直到处理完启动的意图为止。对于已启动的服务,根据从onStartCommand()返回的值,他们可以决定运行两个额外的主要操作模式:START_STICKY用于根据需要显式启动和停止的服务,而使用START_NOT_STICKY或START_REDELIVER_INTENT对于在处理发送给它们的任何命令时应该只保持运行的服务。

bind绑定的service依赖于组件,组件销毁service也随之销毁,需要注意的比如在Activity中bind了service,那么必须在onDestory方法中销毁service调用unBindServie方法。多次调用bind方法只会调用一次onBind()方法,但不会调用onStartCommand()。停止服务是调用了n次bindService,就必须要调用n次unBindService.

5.同一个Service,先startService,然后再bindService,如何把它停止掉?

startService 不论调用几次,只需要stopService(或stopSelf) 一次即可停止掉服务。
如果调用了n次bindService,必须调用n次unBindService 方法,才能停止掉服务。
执行的顺序没有要求。
最后一个stopService(或stopSelf)或者unBindService方法会导致Service的onDestroy方法执行。

6. Service的onStartCommand方法的返回值?不同返回值有什么区别?

一共有四种返回值
START_STICKY_COMPATIBILITY,
START_STICKY,
START_NOT_STICKY,
START_REDELIVER_INTENT,

 /**
     *不保证的{@link #START_STICKY}版本
     * {@link #onStartCommand}在被杀后会再次被调用。
     *为了兼容版本,在service被杀死后,并不保证onStartCommand 会被再次调用
     */
    public static final int START_STICKY_COMPATIBILITY = 0;
    
    /**
    * 如果此service是进程在启动时被杀死(返回后),保持启动状态,但不保留Intent ,之后系统会尝试重启该service,并重新回调
* onStartCommand方法,如果没有其他的start命令,会传递给service 的intent为null,需要注意onStartCommand方法对intent的非空判断
*/ public static final int START_STICKY = 1; /** * 常规操作,除非死之前还有组件调用startService,否则系统不会保留启动状态并重启该service */ public static final int START_NOT_STICKY = 2; /** * service 被杀死后,系统会组织一次service重启(除非之前调用了stopSelf)被杀死之前最后一次传递的intent将被执行,该flag将不会传递空intent,
*这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
*/ public static final int START_REDELIVER_INTENT = 3;

7.Service的生命周期方法onCreate、onStart、onBind等运行在哪个线程?

Service 默认是运行在主线程的,并且其生命周期也是运行在主线程的,所以要想在service中执行耗时操作必须另起一个Thread线程(或者使用IntentService),否则会ANR.





 
 

=======================转==========================
作者:JakePrim
链接:https://www.jianshu.com/p/087415add7a5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自www.cnblogs.com/yz123/p/12007995.html
今日推荐