android四大组件-service全面解析一

来源:互联网 发布:网络建设之歌 编辑:程序博客网 时间:2024/05/19 20:42

Service简介

Service即我们平时所说的服务,Android开发中的四大组件之一,运行于后台,执行一些耗时操作,不与用户直接进行交互。服务可以被其他组件启动,甚至用户切换到其他应用,还能在后台运行。此外,应用程序组件还能绑定服务,并与服务进行交互,甚至进行进程间通信(IPC)。


Service的两种状态

  • Started:如果一个应用程序组件使用startService来启动服务,则该服务处于Started状态。服务一旦被started,则会一直运行在后台,即使启动它的组件销毁了,除非主动调用stopService或者stopSelf。正常情况下,当一个服务结束自己的工作之后,应该立即被终止。
  • Bound:如果一个应用程序的组件使用bindService来绑定服务,则该服务处于Bound状态。bound服务提供了一个客户端/服务器接口,允许启动它的组件和它进行交互,甚至可以进行进程间通信(IPC)、跨进程通信等。绑定服务的生存周期和被绑定的应用程序组件一致,多个组件可以同时绑定一个服务,只有所有的绑定均解除了,服务才会被销毁。

虽然服务有两种状态,但是这两种状态是可以同时存在的,即可以同时以startService和bindService启动服务

注:服务运行于宿主进程的主线程中,不创建自己的线程并且不运行在单独的进程中(除非明确指定),也就是说如果你的服务要执行一些很耗CPU的工作或者阻塞的操作(比如播放MP3或网络操作),你应该在服务中创建一个新的线程来执行这些工作。
利用单独的线程,将减少你的activity发生应用程序停止响应(ANR)错误的风险。


Service和Thread

服务仅仅是一个组件,即使用户不再与你的应用程序发生交互,它仍然能在后台运行。因此,应该只在需要时才创建一个服务。

如果你需要在主线程之外执行一些工作,但仅当用户与你的应用程序交互时才会用到,那你应该创建一个新的线程而不是创建服务。 比如,如果你需要播放一些音乐,但只是当你的activity在运行时才需要播放,你可以在onCreate()中创建一个线程,在onStart()中开始运行,然后在onStop()中终止运行。还可以考虑使用AsyncTask或HandlerThread来取代传统的Thread类。

请记住,如果你使用了服务,它默认就运行于应用程序的主线程中。因此,如果服务执行密集计算或者阻塞操作,你仍然应该在服务中创建一个新的线程来完成。


创建Service

  • 1.创建一个Service的子类,实现一些方法,这些方法取决于以某种方式启动。
  • 2.在AndroidManifiest文件中申明服务,即把元素作为子元素加入到元素中去即可,例如,我们创建了一个播放音乐的服务MusicService,然后去申明它
<manifest ... >  ...  <application ... >      <service android:name=".MusicService" />      ...  </application></manifest>

注:元素中可以包含很多其他属性,如:启动服务的权限,服务运行的进程等,但是android:name是唯一的必需的属性

  • 3.使用startService或bindService启动或绑定一个Service
  • 4.在合适的时机使用stopService、stopSelf、unbindService销毁一个服务。

注:当系统内存少得可怜、且必须覆盖拥有用户焦点的activity的系统资源时,Android系统会强行终止一个服务。 如果服务被拥有用户焦点的activity绑定着,则它一般不会被杀死。如果服务声明为前台运行服务,则它几乎永远不会被杀死。随着服务被启动且运行长时间变成,系统将会随时间推移而降低它在后台任务列表中的级别, 此类服务将很有可能会被杀死——因此你必须在必要的时刻应付被系统重启的情况。 如果系统杀死了你的服务,只要资源再度够用,系统就会再次启动服务(当然这还取决于onStartCommand()的返回值)

创建一个简单的Service:MusicService,并实现一些方法

public class MusicService extends Service {    public static final String TAG = MusicService.class.getSimpleName();    private int mStartMode;       // 标识服务被杀死后的处理方式    private IBinder mBinder = new MyBind();      // 用于客户端绑定的接口    private boolean mAllowRebind; // 标识是否使用onRebind    @Override    public void onCreate() {        // 服务正被创建        Log.i(TAG, "onCreate");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        // 服务正在启动,由startService()调用引发        Log.i(TAG, "onStartCommand");        return mStartMode;    }    @Override    public IBinder onBind(Intent intent) {        // 客户端用bindService()绑定服务        Log.i(TAG, "onBind");        return mBinder;    }    @Override    public boolean onUnbind(Intent intent) {        // 所有的客户端都用unbindService()解除了绑定        Log.i(TAG, "onUnbind");        return mAllowRebind;    }    @Override    public void onRebind(Intent intent) {        // 某客户端正用bindService()绑定到服务,        // 而onUnbind()已经被调用过了        Log.i(TAG, "onRebind");    }    @Override    public void onDestroy() {        Log.i(TAG, "onDestroy");        // 服务用不上了,将被销毁    }    public class MyBind extends Binder {        public MusicService getMusicService() {            return MusicService.this;        }    }}

一个Activity去启动或者绑定MusicService

public class MainActivity1 extends AppCompatActivity implements View.OnClickListener {    private MusicService mMusicService;    private boolean isBind;    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.i(MusicService.TAG, "onServiceConnected");            MusicService.MyBind myBind = (MusicService.MyBind) service;            mMusicService = myBind.getMusicService();            isBind = true;        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i(MusicService.TAG, "onServiceDisconnected");            isBind = false;            mMusicService = null;        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        int[] vClickIds = new int[]{R.id.vBindService, R.id.vStartService,                R.id.vStopService1, R.id.vStopService2, R.id.vUnbindService};        for (int id : vClickIds) {            findViewById(id).setOnClickListener(this);        }    }    @Override    public void onClick(View v) {        int vId = v.getId();        switch (vId) {            case R.id.vStartService:                Intent intent = new Intent(this, MusicService.class);                startService(intent);                break;            case R.id.vBindService:                Intent intent1 = new Intent(this, MusicService.class);                bindService(intent1, mServiceConnection, Service.BIND_AUTO_CREATE);                break;            case R.id.vStopService1:                break;            case R.id.vStopService2:                Intent intent4 = new Intent(this, MusicService.class);                stopService(intent4);                break;            case R.id.vUnbindService:                unbindService(mServiceConnection);                break;        }    }}

StartService

started服务是指其它组件通过调用startService()来启动的服务,这会引发对该服务onStartCommand()方法的调用。

一旦服务被启动started,它就拥有了自己的生命周期,这是独立于启动它的组件的。并且它能够在后台一直运行下去,即使启动它的组件已被销毁 也是如此。 因此,服务应该能够在完成工作后自行终止,通过调用stopSelf()即可,或者由其它组件通过调用stopService()也可以。

诸如activity之类的应用程序组件,可以通过调用startService()启动服务,并传入一个给出了服务和服务所需数据的Intent对象。服务将在onStartCommand()方法中接收到该Intent对象。

此时生命周期的执行过程:onCreate->onStartCommand,如果服务没有被销毁,即没有调用stopService或者stopSelf,那么该组件调用继续调用startService不会再次执行onCreate(),将会继续执行onStartCommand()。但是只有一个终止服务的请求(用stopSelf()或stopService())会被接受并执行

onStartCommand()方法必须返回一个整数。这个整数是描述系统在杀死服务之后应该如何继续运行返回值必须是以下常量之一:

  1. START_NOT_STICKY:如果系统在onStartCommand()返回后杀死了服务,则不会重建服务了,除非还存在未发送的intent。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
  2. START_STICKY:如果系统在onStartCommand()返回后杀死了服务,则将重建服务并调用onStartCommand(),但不会再次送入上一个intent, 而是用null intent来调用onStartCommand() 。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送。 这适用于媒体播放器(或类似服务),它们不执行命令,但需要一直运行并随时待命。
  3. START_REDELIVER_INTENT:如果系统在onStartCommand()返回后杀死了服务,则将重建服务并用上一个已送过的intent调用onStartCommand()。任何未发送完的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。

注:当服务完成工作后,应用程序应该及时终止它,这样可以避免系统资源的浪费,并能节省电池的电力。
必要时,其它组件可以通过调用stopService()来终止服务。即使你的服务允许绑定,你也必须保证它在收到对onStartCommand()的调用时能够自行终止。

BindService

bound服务是指允许被应用程序组件绑定的服务,通过调用bindService()可以完成绑定,用于创建一个长期存在的连接(并且一般不再允许组件通过调用startService()来start服务。

当应用程序中的activity或其它组件需要与服务进行交互,或者应用程序的某些功能需要暴露给其它应用程序时,你应该创建一个bound服务,并通过进程间通信(IPC)来完成。

要创建一个bound服务,你必须实现onBind()回调方法,并返回一个IBinder对象,此对象定义了与服务进行通信的接口。 然后,其它应用程序组件可以调用bindService()来获得接口并调用服务中的方法。 服务只在为绑定的应用程序组件工作时才会存活,因此,只要没有组件绑定到服务,系统就会自动销毁服务(你不需要像started服务中那样通过onStartCommand()来终止一个bound服务)。

要创建一个bound服务,首先必须定义好接口,用于指明客户端如何与服务进行通信。 这个客户端与服务之间的接口必须是一个IBinder对象的实现,并且你的服务必须在onBind()回调方法中返回这个对象。一旦客户端接收到这个IBinder,它就可以通过这个接口来与服务进行交互。

同一个服务可以被多个客户端绑定。当客户端完成交互时,会调用unbindService()来解除绑定。一旦不存在客户端与服务绑定时,系统就会销毁该服务。

当我们bindService时,我们需要创建一个ServiceConnection,并实现其中的两个方法,然后获取到我们绑定的Service,这样启动的组件就可以和Service进行通信了。

private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            Log.i(MusicService.TAG, "onServiceConnected");            MusicService.MyBind myBind = (MusicService.MyBind) service;            mMusicService = myBind.getMusicService();            isBind = true;        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.i(MusicService.TAG, "onServiceDisconnected");            isBind = false;            mMusicService = null;        }    };

bindService时,Service的生命周期:
onCreate->onBind,然后ServiceConnection的onServiceConnected,使用unbindService解绑服务时,会执行onUnbind->onDestory。当服务绑定以后,多次bindService,并不会再次执行onCreate()和onBind(),如果我们并没有bindService并且直接unbindService,则会出现 java.lang.IllegalArgumentException: Service not registered:

StartService和BindService同时存在

一个服务允许同时被start和bind,但是如果一个服务被创建了,且没有被销毁,那么onCreate并不会被再次执行.
例1:先startService然后bindService
生命周期:
这里写图片描述
例2:先bindService,然后stratService
生命周期:
这里写图片描述
例3:先startService然后bindService,然后多次start,多次bind,分别先后尝试stopService和unbindService
生命周期:
这里写图片描述
例4:先bindService,然后stratService,,然后多次start,多次bind,然后分别先后尝试stopService和unbindService
生命周期:
这里写图片描述
结论:服务不管以何种方式被某一个组件创建以后,再次startService,将会继续执行onStartCommand,再次bindService,并不会执行任何方法。只有startService的组件stopService(或者服务自身stopSelf)且bindService的组件unbindService,服务才会终止。

以上就是对Service的简单介绍和生命周期的简单探索,后面我们会探索一些复杂的情况,比如:前台服务、多个组件绑定或启动同一个服务、服务启动的源码等!

希望这篇文章对大家有所帮助!