Android四大组件之Service

前言

Hi,你们好,上一期咱们讲了如何使用BroadcastReceiver,这一期咱们讲解Android四大组件之Service相关知识。天天一篇技术干货,天天咱们一块儿进步。java

耐心专一不只仅是美德,更是一笔财富。android

1.简介与定义

简介

Service是一个能够在后台执行长时间运行操做而不提供用户界面的应用组件。Service可由其余应用组件启动,并且即便用户切换到其余应用,Service仍将在后台继续运行。 此外,组件能够绑定到Service,以与之进行交互,甚至是执行进程间通讯 (IPC)。 例如,Service能够处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而全部这一切都可在后台进行。网络

定义

Service是一个专门在后台处理长时间任务的Android组件。ide

1.Service不是一个单独的进程;函数

2.Service也不是一个单独的线程;this

3.Service是一个单独的Android组件,Service运行在主线程上,若是想在Service中处理很占时间的操做时,必须在Service中开线程,以下降Activity没有响应的风险;spa

4.Service不提供用户界面;操作系统

它有两种启动方式:startServicebindService线程

2.用途

Service有三个常见用途。代理

1.功能调度:Service接收指定的广播信息,从而进一步分析和处理事件,最后修改数据、更新界面或者进行其余相关的操做,调度整个应用使其保持正确的状态。

2.功能提供:Service并不会接收任何的广播,只接收指定的广播提供状态数据,这时须要绑定Service,绑定Service时要管理好Service,通常在Activity的onStop函数里进行解绑unBindService操做。

3.远程调用:定义AIDL服务,跨进程调用Service,先定义一个远程调用接口,而后为该接口提供一个IBinder实现类,客户端获取了远程的Service的IBinder对象的代理后,经过该IBinder对象去回调远程Service的属性或方法。

3.应用场景

若是某个程序组件须要在运行时向用户呈现界面,或者程序须要与用户交互,就须要用Activity,不然就应该考虑使用Service。

4.Service与Activity对比

类似点:

1.都是单独的Android组件;

2.都拥有独立的生命周期;

3.都是Context的派生类,因此能够调用Context类定义的如getResources()getContentResolver()等方法;

4.都拥有本身生命周期回调方法;

不一样点:

1.Activity运行于前台有图形用户界面,负责与用户交互;Service一般位于后台运行,不须要与用户交互,也没有图形用户界面。

5.Service的生命周期

随着应用程序启动Service方式不一样,Service的生命周期也略有差别,以下图:

若是应用程序经过startService()方法来启动Service,Service的生命周期如上图左半部分所示。

经过调用startService() 方法启动Service: 当其余组件调用startService()方法时,Service被建立,而且无限期运行,其自身必须调用stopSelf()方法或者其余组件调用stopService() 方法来中止Service,当Service中止时,系统将其销毁。

若是应用程序经过bindService()方法来启动Service,Service的生命周期如上图右半部分所示。

经过bindService() 方法启动Service: 当其余组件调用bindService()方法时,Service被建立。接着客户端经过IBinder接口与Service通讯。客户端经过unbindService() 方法关闭链接。多个客户端能绑定到同一个Service,而且当他们都解除绑定时,系统将销毁Service(Service不须要被中止)

特别说明:当Activity调用bindService()绑定一个已经过startService()启动的Service时,系统只是把Service内部的IBinder对象传给Activity,并不会把该Service生命周期彻底绑定到该Activity,于是当Activity调用unBindService()方法取消与该Service的绑定时,也只是切断该Activity与Service之间的关联,并不能中止该Service组件。要中止该Service组件,还需调用stopService()方法。

Service的生命周期里,经常使用的有:

4个手动调用的方法

手动调用方法 做用
startService() 启动服务
stopService() 关闭服务
bindService() 绑定服务
unbindService() 解绑服务

5个自动调用的方法

内部自动调用的方法 做用
onCreate() 建立服务
onStartCommand() 开始服务
onDestroy() 销毁服务
onBind() 绑定服务
onUnbind() 解绑服务

6.Service的使用

当咱们开始使用Service的时候固然是启动一个Service了,启动Service的方法和启动Activity很相似,都须要借助Intent来实现,下面咱们就经过一个具体的例子来看一下。

public class MyService extends Service {  
  
    public static final String TAG = "MyService";  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        Log.d(TAG, "onCreate() executed");  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.d(TAG, "onStartCommand() executed");  
        return super.onStartCommand(intent, flags, startId);  
    }  
    
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }
      
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        Log.d(TAG, "onDestroy() executed");  
    }  
  
}  
复制代码

要建立一个这样的Service,你须要让该类继承Service类,而后重写如下方法:

  • onCreate() 1.若是service没被建立过,调用startService()后会执行onCreate()和onStartCommand()方法; 2.若是service已处于运行中,调用startService()不会执行onCreate()方法,只执行onStartCommand()方法。 也就是说,onCreate()只会在第一次建立service时候调用,屡次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工做。
  • onStartCommand() 若是屡次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的屡次调用。onStartCommand()方法很重要,咱们在该方法中根据传入的Intent参数进行实际的操做,好比会在此处建立一个线程用于下载数据或播放音乐等。
  • onBind() Service中的onBind()方法是抽象方法,Service类自己就是抽象类,因此onBind()方法是必须重写的,即便咱们用不到。
  • onDestroy() 在销毁的时候会执行Service的该方法。

这几个方法都是回调方法,且在主线程中执行,由Android操做系统在合适的时机调用。

注意:每一个Service必须在manifest中 经过来声明。

<service android:name="com.demo.service.MyService" > 
  ... 
</service>
复制代码

如今咱们经过继承Service的方式定义了咱们本身的MyService类,而且在manifest中声明了咱们的MyService,接下来咱们应该启动咱们本身的服务。

启动Service

第一种方式:咱们是经过一个Intent对象,并调用startService()方法来启动MyService

Intent startIntent = new Intent(this, MyService.class);  
startService(startIntent); 
复制代码

注意:假如咱们是经过点击Button执行上面的代码,那么第一次点击的时候回执行其中的onCreate()onStartCommand()方法,可是当咱们第二次点击的时候就只会执行onStartCommand()方法。

为何会这样呢? 这是因为onCreate()方法只会在Service第一次被建立的时候调用,若是当前Service已经被建立过了(第一次点击建立了MyService),无论怎样调用startService()方法,onCreate()方法都不会再执行。

第二种方式:经过bindService启动Service

bindService启动服务特色: 1.bindService启动的服务和调用者之间是典型的client-server模式。调用者是clientservice则是server端。service只有一个,但绑定到service上面的client能够有一个或不少个。这里所提到的client指的是组件,好比某个Activity

2.client能够经过IBinder接口获取Service实例,从而实如今client端直接调用Service中的方法以实现灵活交互,这在经过startService()方法启动中是没法实现的。

3.bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定(client会有ServiceConnectionLeaked异常,但程序不会崩溃)。固然,client也能够明确调用ContextunbindService()方法与Service解除绑定。当没有任何clientService绑定时,Service会自行销毁。

启动了以后,当咱们想中止服务的时候该怎么作呢?

中止Service

第一种方式:咱们也是经过一个Intent对象,并调用stopService()方法来中止MyService

Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); 
复制代码

第二种方式:调用unbindService(conn)方法来中止MyService

unbindService(ServiceConnection conn)
复制代码
Service和Activity通讯

在上面咱们高高兴兴的启动了Service了,可是细心的你可能发现了,貌似咱们仅仅只是启动了而已,ActivityService并无多少"交流",下面咱们就让ActivityService交流一下。

public class MyService extends Service {

    public static final String TAG = "MyService";

    private MyBinder mBinder = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() executed");
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy() executed");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    class MyBinder extends Binder {

        public void startDownload() {
            Log.d("TAG", "startDownload() executed");
            // 执行具体的下载任务
        }

    }

}
复制代码

接下来咱们在MainActivity中经过Button来绑定Service和解除绑定

public class MainActivity extends Activity implements OnClickListener {
        
    private Button bindService;

    private Button unbindService;

    private MyService.MyBinder myBinder;

    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (MyService.MyBinder) service;
            myBinder.startDownload();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.bind_service:
            Intent bindIntent = new Intent(this, MyService.class);
            bindService(bindIntent, connection, BIND_AUTO_CREATE);
            break;
        case R.id.unbind_service:
            unbindService(connection);
            break;
        default:
            break;
        }
    }

}
复制代码

能够看到,这里咱们首先建立了一个ServiceConnection的匿名类,在里面重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在ActivityService创建关联和解除关联的时候调用。在onServiceConnected()方法中,咱们又经过 向下转型 获得了MyBinder的实例,有了这个实例,ActivityService之间的关系就变得很是紧密了。如今咱们能够在Activity中根据具体的场景来调用MyBinder中的任何public方法,即实现了Activity指挥Service干什么Service就去干什么的功能。

固然,如今ActivityService其实还没关联起来了呢,这个功能是在Bind Service按钮的点击事件里完成的。能够看到,这里咱们仍然是构建出了一个Intent对象,而后调用bindService()方法将ActivityService进行绑定。bindService()方法接收三个参数,第一个参数就是刚刚构建出的Intent对象,第二个参数是前面建立出的ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在ActivityService创建关联后自动建立Service,这会使得MyService中的onCreate()方法获得执行,但onStartCommand()方法不会执行(只有当咱们经过 startService()方法请求启动服务时,调用此方法)。

解除Activity和Service之间的关联,调用

unbindService(connection);  
复制代码
关于销毁Service说明
  • MyService的内部经过stopSelf()方法来销毁的;

  • 一个Service必需要在既没有和任何Activity关联又处理中止状态的时候才会被销毁;

  • 在Service的onDestroy()方法里去清理掉那些再也不使用的资源,防止在Service被销毁后还会有一些再也不使用的对象仍占用着内存;

7.IntentService

IntentService是Service的子类,在介绍IntentService以前,先来了解使用Service时须要注意的两个问题

  • Service 不会专门启动一个线程执行耗时操做,全部的操做都是在主线程中进行的,以致于容易出现ANR,因此须要手动开启一个子线程;
  • Service 不会自动中止,须要调用stopSelf()方法 或者 是stopService() 方法中止;

使用IntentService不会出现这两个问题,由于IntentService在开启Service时,会自动开启一个新的线程来执行它,另外,当Service运行结束后,会自动中止。

8.如何保证服务不会被杀死

第一种方式,返回 START_STICKYSTART_REDELIVER_INTENT

Service因内存不足而被系统kill后,一段时间后内存再次空闲时,系统将会尝试从新建立此Service,一旦建立成功后将回调onStartCommand方法,但其中的Intent将是null,除非有挂起的Intent,如pendingintent,这个状态下比较适用于不执行命令、但无限期运行并等待做业的媒体播放器或相似的服务。

/** * 返回 START_STICKY 或 START_REDELIVER_INTENT * @param intent * @param flags * @param startId * @return */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //return super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

复制代码

第二种方式,提升service的优先权

<service  
    android:name="com.demo.UploadService"  
    android:enabled="true" >  
    <intent-filter android:priority="1000" >  
        <action android:name="com.demo.MyService" />  
    </intent-filter>  
</service>

复制代码

结语

Service做为Android的四大组件之一,而且项目开发过程当中一些场景下常常被使用到,小伙伴们赶忙上手实操,把它灵活的运用到项目中,结合上两期的Activity和BroadcastReceiver实现有趣的交互吧。
PS:若是还有未看懂的小伙伴,欢迎加入咱们的QQ技术交流群:892271582,里面有各类大神回答小伙伴们遇到的问题哦~

相关文章
相关标签/搜索