溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android?Service怎么實現

發(fā)布時間:2023-01-03 10:18:00 來源:億速云 閱讀:108 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下Android Service怎么實現的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    一.APP側啟動Service

    其實啟動service和啟動Activity是很相似的,都是APP通知系統(tǒng)側,由系統(tǒng)側完成的整個流程。

    1.1 前臺和后臺啟動

    無論是Activity,還是service,還是Application,都繼承自Context的抽象類,所以可以使用Context的各種功能,就比如這了要介紹的啟動前臺/后臺service。

    Context在安卓中,使用了一種典型的代理模式,我們調用的startService或者startForegroundService方法,最終都會委托給ContextImpl中的startService和startForegroundService來處理的。我們就來看下ContextImpl中的這兩個方法:

    @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, false, mUser);
        }
        @Override
        public ComponentName startForegroundService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, true, mUser);
        }

    果然和我猜測的差不多,無論前臺還是后臺啟動,其實最終都會走到一個方法中,只是配置參數的區(qū)別而已。最終都會走執(zhí)行startServiceCommon方法。

    1.2startServiceCommon

    該方法中,通過binder通知系統(tǒng)的AMS完成對應的service的啟動操作:

     ComponentName cn = ActivityManager.getService().startService(
                        mMainThread.getApplicationThread(), service,
                        service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                        getOpPackageName(), getAttributionTag(), user.getIdentifier());

    接下來,我們就看下系統(tǒng)側是如何處理Service啟動流程的。

    二.系統(tǒng)側分發(fā)處理Service的啟動邏輯

    系統(tǒng)側的處理我主要分為3塊來講:

    1.系統(tǒng)接受APP側的通知并轉發(fā)

    2.系統(tǒng)側委托ActiveServices負責完成的處理流程

    3.收到APP側執(zhí)行完成的回調,進行收尾操作

    2.1 AMS接受啟動service的通知

    APP側持有system_server進程的binder,上面講到,它會通過binder方法startService完成對系統(tǒng)側的通知。所以AMS的startService會收到這個通知。

    我們看下代碼,發(fā)現AMS會把整個service的邏輯全部交由ActiveServices來處理,代碼如下:

     try {
                    res = mServices.startServiceLocked(caller, service,
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, callingFeatureId, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }

    系統(tǒng)代碼startServiceLocked方法中,代碼雖然很長,但是卻遵循著一個不變的宗旨:位語句,即前面處理各種異常的分支邏輯,把核心流程留到方法的最終來處理。

    所以我們直接看startServiceLocked方法的最后一部分即可:

    final ComponentName realResult =
                    startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                    allowBackgroundActivityStarts, backgroundActivityStartsToken);

    startServiceInnerLocked方法中,處理邏輯也是比較簡單的,最終會交給bringUpServiceLocked方法來進行處理。而bringUpServiceLocked方法中則最終會交給realStartServiceLocked完成整個流程。好像系統(tǒng)代碼都喜喜歡用realStart,Activity啟動的流程中也有一個方法叫realStartActivity。

    2.2realStartServiceLocked流程

    realStartServiceLocked方法中,我們總結為三個流程:

    1.bumpServiceExecutingLocked,啟動超時檢查。

    2.thread.scheduleCreateService通知APP一側去創(chuàng)建Service。

    3.sendServiceArgsLocked通知APP執(zhí)行Service的生命流程。

    private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
                IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
                boolean enqueueOomAdj) throws RemoteException {
            //1.啟動超時檢查
            bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
            ...
            //2.通知APP創(chuàng)建service
                thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                        app.mState.getReportedProcState());
                r.postNotification();
                created = true;
            ...
            //3.通知執(zhí)行service生命流程
            sendServiceArgsLocked(r, execInFg, true);
           ...
        }

    三.系統(tǒng)側通知APP啟動Service

    一般情況下,APP側會收到系統(tǒng)側發(fā)過來兩種類型的通知,

    第一種:創(chuàng)建Service的任務通知

    第二種:執(zhí)行Service生命流程的通知,通知Service執(zhí)行onStartCommand方法。

    ApplicationThread接受通知并創(chuàng)建Service

    系統(tǒng)側持有APP側的binder,會通過scheduleCreateService這個binder方法通知APP一側進行相應的操作。而APP側,完成這個工作接收的就是ApplicationThread中的scheduleCreateService方法。該方法收到通知后,通過handler切換到主線程處理:

     public final void scheduleCreateService(IBinder token,
                    ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
                updateProcessState(processState, false);
                CreateServiceData s = new CreateServiceData();
                s.token = token;
                s.info = info;
                s.compatInfo = compatInfo;
                sendMessage(H.CREATE_SERVICE, s);
            }

    handle中,會切換到主線程執(zhí)行ActivityThread的handleCreateService方法。

    主要執(zhí)行了如下的幾段邏輯:

    1.如果是首次創(chuàng)建App進程的話,則需要重新創(chuàng)建Application;

    2.創(chuàng)建Service對象;

    3.調用service的attach方法進行關聯;

    4.調用service的onCreate生命周期方法;

    5.創(chuàng)建完成后,通過serviceDoneExecuting通知系統(tǒng)側創(chuàng)建完成。

    try {
                if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
                Application app = packageInfo.makeApplication(false, mInstrumentation);
                final java.lang.ClassLoader cl;
                if (data.info.splitName != null) {
                    cl = packageInfo.getSplitClassLoader(data.info.splitName);
                } else {
                    cl = packageInfo.getClassLoader();
                }
                service = packageInfo.getAppFactory()
                        .instantiateService(cl, data.info.name, data.intent);
                ContextImpl context = ContextImpl.getImpl(service
                        .createServiceBaseContext(this, packageInfo));
                if (data.info.splitName != null) {
                    context = (ContextImpl) context.createContextForSplit(data.info.splitName);
                }
                if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
                    final String attributionTag = data.info.attributionTags[0];
                    context = (ContextImpl) context.createAttributionContext(attributionTag);
                }
                // Service resources must be initialized with the same loaders as the application
                // context.
                context.getResources().addLoaders(
                        app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
                context.setOuterContext(service);
                service.attach(context, this, data.info.name, data.token, app,
                        ActivityManager.getService());
                service.onCreate();
                mServicesData.put(data.token, data);
                mServices.put(data.token, service);
                try {
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }

    ApplicationThread接受通知并執(zhí)行Service的生命流程

    同樣的,這里完成接受的是,仍然是ApplicationThread中的方法。這個流程中的接受方法是scheduleServiceArgs方法。

    ApplicationThread中,收到通知后,通過handler把任務轉交到主線程。

     public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
                List<ServiceStartArgs> list = args.getList();
                for (int i = 0; i < list.size(); i++) {
                    ServiceStartArgs ssa = list.get(i);
                    ServiceArgsData s = new ServiceArgsData();
                    s.token = token;
                    s.taskRemoved = ssa.taskRemoved;
                    s.startId = ssa.startId;
                    s.flags = ssa.flags;
                    s.args = ssa.args;
                    sendMessage(H.SERVICE_ARGS, s);
                }
            }

    接下來handler中切換到主線程會執(zhí)行ActivityThread的handleServiceArgs方法。

    handleServiceArgs方法主要會完成以下幾件事:

    1.找到對應的service,調用起onStartCommand方法;

    2.通知系統(tǒng)側回調完成。

    private void handleServiceArgs(ServiceArgsData data) {
            CreateServiceData createData = mServicesData.get(data.token);
            Service s = mServices.get(data.token);
            if (s != null) {
                try {
                    if (data.args != null) {
                        data.args.setExtrasClassLoader(s.getClassLoader());
                        data.args.prepareToEnterProcess(isProtectedComponent(createData.info),
                                s.getAttributionSource());
                    }
                    int res;
                    if (!data.taskRemoved) {
                        res = s.onStartCommand(data.args, data.flags, data.startId);
                    } else {
                        s.onTaskRemoved(data.args);
                        res = Service.START_TASK_REMOVED_COMPLETE;
                    }
                    QueuedWork.waitToFinish();
                    try {
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                } catch (Exception e) {
                    if (!mInstrumentation.onException(s, e)) {
                        throw new RuntimeException(
                                "Unable to start service " + s
                                + " with " + data.args + ": " + e.toString(), e);
                    }
                }
            }
        }

    以上就是“Android Service怎么實現”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI