Android 四大组件之Service

Android 四大组件之Service

   上篇博客,我们讲解了关于Activity我们应该知道的知识,这篇文章,我们继续往下学习,了解关于Service的“前世今生”。

一 Service的种类

按照运行地点,运行类型,以及使用方式上,我们可以将Service这样划分。

a.按照运行地点

类别

区别

优点

缺点

应用

  本地服务(Local)

该服务依附在主进程上

 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,相应bindService会简单很多。

 主进程被Kill后,服务便会终止。

 常见的应用如:音乐播放服务。

  远程服务(Remote)

该服务是独立的进程

 服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。

 该服务是独立的进程,会占用一定资源,并且IPC稍微麻烦一点。

 一些提供系统服务Service,这种Service是常驻的。

 

b.运行类型

类别

区别

应用

前台服务

会在通知一栏显示 ONGOING 的 Notification,

当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。常见的如音乐播放服务。

后台服务

默认的服务即为后台服务,即不会在通知一栏显示 ONGOING的 Notification。

当服务被终止的时候,用户是看不到效果的。某些不需要运行或终止提示的服务,如天气更新,日期同步,邮件同步等。

   

   服务需要调用 startForeground ( android 2.0 及其以后版本 )或 setForeground (android 2.0 以前的版本)使服务成为前台服务。

 

 

 

c.使用方式

类别

区别

startService 启动的服务

主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService

bindService 启动的服务

该方法启动的服务要进行通信。停止服务使用unbindService

startService 同时也 bindService 启动的服务

停止服务应同时使用stopService与unbindService

 

二 Service 与 Thread 的区别

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上

 

我们可以将Service理解成比Thread更高级的东西。Thread在一个Activity中启动后,无法与另外一个Activity通信,因为其他Activity无法知道Thread的存在。而Service是与Activity同等重要的组件,它在后台默默的位应用提供服务,任何Activity需要“接收”它的服务都可以。另外Service更不容易被系统杀死,可以长期的在后台执行任务。

 

三 Service的生命周期

Service常用的方法有onCreateonStartonDestroyonBind 。根据不同的使用情况,我们可以这样理解:

 

 

(1). 被启动的服务的生命周期:如果一个Service被Activity调用startService启动的话,onCreate,onStart方法会依次调用,而如果该Activity多次调用startService的话,由于该Service已经存在,onCreate不会再被调用,而onStart会被再次调用。并且系统只创建一个实例。该Service会一直存在在后台,而与调用它的Activity无关,直到stopService或者stopSelf被调用或者被系统杀死。

(2).被绑定的服务的生命周期:如果Service被一个Activity调用bindService方法启动,不管调用bindService几次,onCreate方法都只会调用一次,因为Service已经存在,而onStart方法始终不会调用(需牢记).当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

(3).被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。

(4).当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动)时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程若服务先被启动,然后绑定到一个Activity上,则该Activity的销毁不会造成服务被清除

(5).注意:同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;另外,当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

 

四 Local 与 Remote 服务绑定

记得在 Androidmanifest.xml 中注册 service

(1).Local 服务绑定:Local 服务的绑定较简单,首先在 Service 中我们需要实现 Service 的抽象方法 onBind(所以该方法一定要重写),并返回一个实现 IBinder 接口的对象。Binder可以理解为C#中的代码块。Binder对象在Service中实例化,当与Activity建立连接后,可以在Activity中调用返回到Activity中的binder,从而可以调用binder包含的方法。

Service的代码:

package cn.tyssen.test;

 

import android.app.Service;

import android.content.Intent;

import android.os.Binder;

import android.os.IBinder;

 

public class LocalService extends Service {

 

    /**

     * 在 Local Service 中我们直接继承 Binder 而不是 IBinder,因为 Binder 实现了 IBinder 接口,这样我们可以少做很多工作。

     * @author newcj

     */

    public class SimpleBinder extends Binder{

        /**

         * 获取 Service 实例

         * @return

         */

        public LocalService getService(){

            return LocalService.this;

        }

         

        public int add(int a, int b){

            return a + b;

        }

    }

     

    public SimpleBinder sBinder;

     

    @Override

    public void onCreate() {

        super.onCreate();

        // 创建 SimpleBinder

        sBinder = new SimpleBinder();

    }

     

    @Override

    public IBinder onBind(Intent intent) {

        // 返回 SimpleBinder 对象

        return sBinder;

 

/*Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected 不会被调用,但你任然需要使用 unbindService 函数断开它,这样 Service 才会停止。*/

    }

 

}

上面onBind(Intent) 这个方法 返回了一个实现了 IBinder 接口的对象,这个对象将用于绑定Service 的 Activity 与 Local Service 通信。

下面是 Activity 中的代码:

package cn.tyssen.test;

 

import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.IBinder;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

 

public class Main extends Activity {

    private final static String TAG = "SERVICE_TEST";

    private ServiceConnection sc;

    private boolean isBind;

 

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        sc = new ServiceConnection() {

             

            @Override

            public void onServiceDisconnected(ComponentName name) {

 

            }

             

            @Override

            public void onServiceConnected(ComponentName name, IBinder service) {

 LocalService.SimpleBinder sBinder = (LocalService.SimpleBinder)service;

                Log.v(TAG, "3 + 5 = " + sBinder.add(3, 5));

                Log.v(TAG, sBinder.getService().toString());

            }

        };

        findViewById(R.id.btnBind).setOnClickListener(new OnClickListener() {

             

            @Override

            public void onClick(View v) {

                bindService(new Intent(Main.this, LocalService.class), sc, Context.BIND_AUTO_CREATE);

                isBind = true;

            }

        });

        findViewById(R.id.btnUnbind).setOnClickListener(new OnClickListener() {

             

            @Override

            public void onClick(View v) {

//unbindService 解除绑定,参数则为之前创建的 ServiceConnection 接口对象。//另外,多次调用 unbindService 来释放相同的连接会抛出异常,因此我创建了一个 //boolean 变量来判断是否 unbindService 已经被调用过。

 

                if(isBind){

                    unbindService(sc);

                    isBind = false;

                }

            }

        });

    }

}

 

(2).Remote 服务绑定:Remote 的服务绑定由于服务是在另外一个进程,因此需要用到 android 的 IPC 机制。我会再写另一系列文章讲Android的IPC机制与常用IPC方法。

 

五  如何使用startService 或 bindService

如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择使用 bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。

 

在 AndroidManifest.xml 里 Service 元素的常见选项

android:name  -------------  服务类名

android:label  --------------  服务的名字,如果此项不设置,那么默认显示的服务名则为类名

android:icon  --------------  服务的图标

android:permission  -------  申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process  ----------  表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字

android:enabled  ----------  如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported  ---------  表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值