Android四大基本组件-Service详解

一、官方文档

Class Overview

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package’s AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().

服务是一种应用程序组件代表应用程序的意图,而不是与用户或其他应用程序使用电源的功能执行更长的运行操作。每个服务类必须有一个相应的服务声明在其AndroidManifest.xml。启动服务的方法有startservice(), bindservice()。后面会有具体事例测试这两种方法的使用。

Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Application Fundamentals: Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.

注意,服务是运行在他们的主进程的主线程。这意味着,如果你的服务是要做任何CPU消耗大的操作(如MP3播放)或阻塞(如网络)的操作,它会以它自己的线程去做这项工作。关于这方面的更多信息可以在应用基础:进程和线程。intentservice类可以作为一个标准的服务实现,可以调度自己的线程去工作。

What is a Service?

Most confusion about the Service class actually revolves around what it is not:

  • A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
  • A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

    这里要说的是我们不仅要知道service是什么,还要知道它不是什么.

  • 服务不是一个单独的进程。服务对象本身并不意味着它是在它自己的进程中运行;除非另有规定,它运行在同一进程中的应用就是它的一部分。
  • 服务不是一个线程。这并不意味着主线程去完成相应工作(避免应用程序无响应的错误)

    Thus a Service itself is actually very simple, providing two main features:

  • A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.
  • A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.
  • 用于告诉系统什么要在后台运行(即用户不直接与应用程序交互),调用Context.startService() 启动服务,这要求系统来管理该服务,该服务会一直运行到知道明确停止它为止,即stopService()。
  • 一个应用程序提供它的一些功能给其他的应用。可以调用Context.bindService()来绑定服务,它允许一个长期的连接是为了服务与它进行交互。(操作中会获得service的binder对象,通过binder来调用相关的服务)

    When a Service component is actually created, for either of these reasons, all that the system actually does is instantiate the component and call its onCreate() and any other appropriate callbacks on the main thread. It is up to the Service to implement these with the appropriate behavior, such as creating a secondary thread in which it does its work.

    Note that because Service itself is so simple, you can make your interaction with it as simple or complicated as you want: from treating it as a local Java object that you make direct method calls on (as illustrated by Local Service Sample), to providing a full remoteable interface using AIDL.

    当一个服务组件被创造时,系统都会调用它的oncreate()和主线程的任何其他适当的回调。它是由服务来实现这些与适当的行为,如创建一个辅助线程来完成它的工作。

    值得注意的是,由于服务本身那么简单,你可以用service与其他应用或其他组件实现一些或简单或复杂的交互:比如要为本地Java对象你直接调用方法,也可以调用AIDL接口进行进程间操作。

Service Lifecycle 服务的生命周期

There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.

有两个理由可以说明服务可以被系统运行。如果有人Context.startService()来启动服务。然后系统会检索服务(创造它,如果需要调用它的oncreate()方法)然后调用onStartCommand(Intent, int, int) 方法。然后该服务将一直运行,直到stopservice()或stopself()被调用。请注意,当服务启动后,再调用Context.startService() 方法时,(onstartcommand()会被调用oncreate()方法不会再次被调用,也就是说服务只会被创建一次,然调用stopservice()或stopself()会停止服务;然而,服务可以用stopSelf(int)来保证服务直到成功打开意图之后才停止。

For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them.

为启动的服务,有两个主要的操作模式,他们可以决定运行,取决于他们的回报onstartcommand()价值:start_sticky用于显式启动和停止所需要的服务,而start_not_sticky或start_redeliver_intent用于服务,应运行在处理任何命令发送给他们。

Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service’s IBinder). Usually the IBinder returned is for a complex interface that has been written in aidl.

客户端也可以使用Context.bindService() 获得持久连接到服务。这同样造成服务如果它没有运行(虽然这样叫oncreate()),但不调用onstartcommand()。客户端将从onBind(Intent)方法得到IBinder对象,让绑定者可以调用相关服务。该服务被创建后将和绑定者保持连接(不管客户端是否仍保留服务的IBinder)。通常返回的是一个复杂的接口,这个已经在AIDL中实现。

A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service’s onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().

对于一个服务的绑定者,服务既可以被开启,也可以被连接。在这种情况下,系统会保持服务的运行只要是开始或有一个或多个连接到它的context.bind_auto_create标识。一旦这些情况都存在,服务的ondestroy()方法被调用后,服务才会有效终止。这样,所有的清理(停止线程,注销接收器)等方法都可以卸载ondestroy()中。

Process Lifecycle 进程周期

The Android system will attempt to keep the process hosting a service around as long as the service has been started or has clients bound to it. When running low on memory and needing to kill existing processes, the priority of a process hosting the service will be the higher of the following possibilities:

Android系统会试图让进程托管服务当这个服务被开启或被绑定时。在低内存的时候需要杀死现有的进程,一个托管了服务将的进程优先级更高:

If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.

如果服务是目前正在执行oncreate()、onstartcommand()或ondestroy()方法,然后宿主进程将变成前台进程以确保这些方法能被执行而不被杀死。

If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in extreme low memory conditions.

如果此服务已被启动,任何可见进程都比它的宿主进程更重要,但比那些不可见的进程都要重要。因为只有很少的进程是可见进程,这表明服务应该不会在极端低内存情况下被杀死。

If there are clients bound to the service, then the service’s hosting process is never less important than the most important client. That is, if one of its clients is visible to the user, then the service itself is considered to be visible.

如果有客户端绑定到服务,那么服务的宿主进程比这些重要的客户端还重要。也就是说,如果绑定它的一个客户端是用户可见的,那么服务本身是可见的。

A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)

一个启动的服务可以使用startForeground(int, Notification) API把服务设置为前台状态,系统认为是用户的主动意识,所以在内存不足时,该服务并不是被杀候选人。(这仍然是理论上可能的,在内存极端不足时,即便是前台service也有可能被杀。)

Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory pressure. If this happens, the system will later try to restart the service. An important consequence of this is that if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it.

注意,大部分时间你的服务一直在运行,在内存压力非常大的时候它也会被杀死。如果发生这种情况,系统将尝试重新启动服务。这是一个重要的结果,如果你实现onstartcommand()安排工作要在另一个线程异步完成,那么你可能想使用start_flag_redelivery让系统为你提供一个意图使它不会丢失之前的服务。

二、具体实例

1.最基本的用法

package com.servicedetail;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void StartService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        startService(startIntent);

    }

    public void StopService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        stopService(startIntent);
    }
}
package com.servicedetail;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("--","onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("--","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("--","onBind");
        return null;
    }

    @Override
    public void onDestroy() {
        Log.i("--","onDestroy");
        super.onDestroy();
    }
    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("--","onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        Log.i("--","onRebind");
        super.onRebind(intent);
    }

}

—–>最简单的startService, stopService

第一次点击startService,stopService:

在destroy之前点击两次startService,只会调用一次onCreate方法

这是由于onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行。因此你可以再多点击几次StartService按钮试一次,每次都只会有onStartCommand()方法中的打印日志

2.Service和Activity通信

上面我们学习了Service的基本用法,启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑了。不过这样的话Service和Activity的关系并不大,只是Activity通知了Service一下:“你可以启动了。”然后Service就去忙自己的事情了。那么有没有什么办法能让它们俩的关联更多一些呢?比如说在Activity中可以指定让Service去执行什么任务。当然可以,只需要让Activity和Service建立关联就好了。

观察MyService中的代码,你会发现一直有一个onBind()方法我们都没有使用到,这个方法其实就是用于和Activity建立关联的,修改MyService中的代码,如下所示:

package com.servicedetail;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {

    private MyService.MyBinder myBinder;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("--", "MainActivity-->onServiceConnected");
            myBinder = (MyService.MyBinder) service;
            myBinder.conServer();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("--", "MainActivity-->onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void StartService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        startService(startIntent);

    }

    public void StopService(View v) {
        Intent startIntent = new Intent(this, MyService.class);
        stopService(startIntent);
    }

    public void BindService(View v) {
        Intent bindIntent = new Intent(this, MyService.class);
        bindService(bindIntent, connection, BIND_AUTO_CREATE);
    }

    public void UnbindService(View v) {
        if (connection != null)
            unbindService(connection);
    }
}

运行效果:

(1):点击BindService

再点击UnbindService

—>可以看到activity和service建立连接了,而且这种步骤会destroy掉service。

(2):点击startService,在点击BindService ,再点击UnbindService,可以看到不会destroy掉service

如果再点击stopService就会destroy service。

3.如何销毁Service

在Service的基本用法这一部分,我们介绍了销毁Service最简单的一种情况,点击Start Service按钮启动Service,再点击Stop Service按钮停止Service,这样MyService就被销毁了,可以看到打印日志如下所示:

Service-->onCreateService
Service-->onStartCommand
Service-->onDestroy

那么如果我们是点击的Bind Service按钮呢?由于在绑定Service的时候指定的标志位是BIND_AUTO_CREATE,说明点击Bind Service按钮的时候Service也会被创建,这时应该怎么销毁Service呢?其实也很简单,点击一下Unbind Service按钮,将Activity和Service的关联解除就可以了。

先点击一下Bind Service按钮,再点击一下Unbind Service按钮,打印日志如下所示:

Service-->onCreate
Service-->onBind
Service-->onUnbind
Service-->onDestroy

以上这两种销毁的方式都很好理解。那么如果我们既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。

4.创建前台Service

Service几乎都是在后台运行的,一直以来它都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如QQ或微信等聊天的会在通知栏提示收到信息。

在onCreate()方法中或onBind()方法中添加如下代码:

Notification notification = new Notification(R.drawable.ic_launcher,    "有通知到来", System.currentTimeMillis());
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);
        notification.setLatestEventInfo(this, "通知标题", "通知内容", pendingIntent);
        startForeground(1, notification);

在开启服务要调用startService()后,在通知栏会保持一个通知(只要不调用stopService(),就会一直处在通知栏);,这是即使程序关闭,都不会消失。 如果调用bindService,程序关闭,服务就会关闭。

最后需要注意的是:

上面的官方文档已经说了,service不是一个单独的线程,也就是说service就在主线程中,所以如果要处理耗时操作的话,主线程肯定会卡。所以,在service中处理耗时操作也要新开一个线程。那为什么不直接在activity中开一个线程来处理呢?

原因有:

1.activity难以控制线程,一旦activity销毁后,之前创建的进程就无法再次获得。

2.在一个activity中创建的线程无法被另一个activity操作。

3.Service可以很好的管理线程,即使activity销毁了,只要再次绑定service还可以通过service操作处理事务的线程。

源码

时间: 2024-11-03 15:22:07

Android四大基本组件-Service详解的相关文章

Android官方架构组件:Lifecycle详解&迪士尼彩乐园网站架设原理分析

我们先将重要的这些类挑选出来: LifecycleObserver接口( Lifecycle观察者):实现该接口的类,通过注解的方式,可以通过被LifecycleOwner类的addObserver(LifecycleObserver o)方法注册,被注册后,LifecycleObserver便可以观察到LifecycleOwner的生命周期事件. LifecycleOwner接口(Lifecycle持有者):实现该接口的类持有生命周期(Lifecycle对象),该接口的生命周期(Lifecyc

Android官方架构组件:Lifecycle详解&迪士尼彩乐园平台搭建原理分析

在过去的谷歌IO大会上,Google官方向我们推出了 Android Architecture Components,其中谈到Android组件处理生命周期的问题,向我们介绍了 Handling Lifecycles. 同时,如何利用 android.arch.lifecycle 包提供的类来控制数据.监听器等的 lifecycle.同时,LiveData 与 ViewModel 的 lifecycle 也依赖于 Lifecycle 框架. 经过公司内部的技术交流小组的探讨后,不少小伙伴觉得这个

Android官方架构组件:Lifecycle详解&迪士尼彩乐园定制开发原理分析

Lifecycle 是一个类,它持有关于组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他对象观察此状态. 我们只需要2步: 1.Prestener继承LifecycleObserver接口public interface IPresenter extends LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) void onCreate(@NotNull LifecycleOwner

android四大基础组件--Service生命周期详解

android四大基础组件--ServiceService 生命周期详解 1.Service的生命周期: I> 在非绑定Service情况下,只有oncreate(),onStartCommand(),onDestory()方法情况下:  操作方法对应生命周期一: a.[执行startService(Intent)] 执行生命周期方法:oncreate()--->onStartCommand(): b.[执行stopService(Intent)] 执行生命周期方法:onDestory();

Android四大视图动画图文详解

Android中的动画分为视图动画(View Animation).属性动画(Property Animation)以及Drawable动画. Android从最初的版本就支持视图动画,视图动画顾名思义,就是应用在视图View上的动画.视图动画的核心类是android/view/animation/Animation,该类是一个抽象类,该类有五个子类,分别是AlphaAnimation.TranslateAnimation.RotateAnimation.ScaleAnimation.Anima

Android 四大组件之Service详解

                   Android四大组件之Service详解    来这实习已经10多天了,今天整理整理学习时的Android笔记.正所谓好记性不如烂笔头,今天来说说service组件. service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的. Service是在一段不定的时间运行在后台,不和用户交互应用组件.每个

Android四大组件--Activity详解

Android四大组件--Activity详解 分类: android android应用android开发 本文的主要内容包括1.activity的建立.配置和使用:2.activity的跳转和传值:3.startActivityForResult:4.activity的生命周期. 1.activity的建立.配置和使用 Activity是一个应用中的组件,它为用户提供一个可视的界面,方便用户操作,比如说拔打电话.照相.发邮件或者是浏览地图等.每个activity会提供一个可视的窗口,一般情况

Android开发四大组件--Activity详解

Android开发四大组件--Activity详解 - Android开发教程 Android开发的四大组件在开发中应用中是必不可少的,下面就来详解下四大组件之一Activity,总结自网络.Activty的生命周期的也就是它所在进程的生命周期. 一个Activity的启动顺序: onCreate()——>onStart()——>onResume() 当另一个Activity启动时: 第一个Activity onPause()——>第二个Activity onCreate()——>

Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送,写这个系列真的很要命,你要去把他们的API文档大致的翻阅一遍,而且各种功能都实现一遍,解决各种bug各种坑,不得不说,极光推送真坑,大家使用还是要慎重,我们看一下极光推送的官网 https://www.jpush.cn/common/ 推送比较使用,很多软件有需要,所以在这个点拿出来多讲讲,我们本节