三十、Android Service介绍

Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序,Service与Activity的区别在于: Service一直在后台运行,它没有用户界面,所以绝不会到前台来。一旦Service被启动起来之后,它就与 Activity一样。它完全具有自己的生命周期。关于程序中Activity与 Service的选择标准是:如果某个程序组件需要在运行时向用户呈现某种界面,或者该程序需要与用户交互,就需要使用 Activity,否则就应该考虑使用 Service了。

开发者开发Service的步骤与开发Aciy的步骤很像,开发Service组件需要先开发个Service的子类,然后在Androidmanifest.xml文件中配置该 Service,配置时可通过<Intent- filter.../>元素指定它可被哪些Intent启动。

Android系统本身提供了大量的 Service组件,开发者可通过这些系统 Service来操作Android系统本身。

开发Service两个步骤:
定义一个继承Service的子类;
在Androidmanifest.xml文件中配置该Service

public class FirstService extends Service {
    
    /*
     * 该方法是Service子类必须实现的方法。
     * 该方法返回一个IBinder对象,应用程序
     * 可通过该对象与Service组件通信。
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //当该Service第一次被创建时回调该方法
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("Service is Created");
    }

    //每次客户端调用startService(Intent)方法启动该Service时都会调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("Service is Started");
        return START_STICKY;
    }

    //当该Service上绑定的所有客户端都断开连接时将会回调该方法
    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    //Service被关闭之前回调
    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("Service is Destroyed");
    }
}

配置Service 使用<service.../>。与配置Activity相似,配置Service时也可为<service.../>元素配置<intent-filter.../>,用于说明该Service可被哪些Intent启动。

<service android:name=".service.FirstService">
    <intent-filter>
         <action android:name="com.myandroid.service.FIRST_SERVICE"/>
    </intent-filter>
</service>

当该 Service开发完成之后,接下来就可在程序中运行该 Service了, Android系统中运行 Service有如下两种方式:

1.通过 Context 的 startservice()方法:通过该方法启用 Service,访问者与 Service
之间没有关联,即使访问者退出了, Service仍然运行。

2.通过 Context 的 bondservice0方法:使用该方法启用 Service,访问者与 Service
绑定在了一起,访问者一且退出, Service也就终止下面先示范的第一种方式运行 Service。

启动停止Service
public class Activity25 extends BaseActivity implements View.OnClickListener {

    public Intent intent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity25);
        Button start = findViewById(R.id.start);
        Button stop = findViewById(R.id.stop);
        /*
         * 服务意图必须是显性声明。 这是为了防止造成冲突(有多个Service用同样的intent-filter的情况)
         * 这是Android 5.0 (Lollipop) 之后的规定。不能用包名的方式定义Service Intent, 而要用显
         * 性声明:new Intent(context, xxxService.class);
         *
         * 如果想继续使用隐式意图的话,加上包名信息即可
         */
        intent = new Intent();
        intent.setAction("com.myandroid.service.FIRST_SERVICE");
        intent.setPackage(context.getPackageName());//兼容Android 5.0
        start.setOnClickListener(this);
        stop.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.start:
                startService(intent);
                break;
            case R.id.stop:
                stopService(intent);
                break;
        }
    }
}
绑定本地Service并与之通信

当程序通过 startservice()和 stopservice()启动、关闭 Service时, Service与访问者之间基本上不存在太多的关联,因此 Service和访问者之间也无法进行通信、数据交换。

如果Service和访问者之间需要进行方法调用或数据交换,则应该使用bindService()和unbindService()方法启动、关闭服务。

Context的bindService()方法的完整方法签名为: bindService(Intent service,Serviceconnection conn. int flags)该方法的三个参数的解释如下:

service:该参数通过Intent指定要启动的Service
con:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service
之间的连接情况。当访问者与Service之间连接成功时将回调该Serviceconnection对象的onServiceConnected(ComponentName name, IBinder service)方法;当访问者与Service之间断开连接时将回调该ServiceConnection对象的onServiceDisconnected(ComponentName name)方法。
flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定为0(不自动创建)或BIND_AUTO_ CREATE(自动创建)。

public class BindService extends Service {

    private int count;

    private boolean quit;
    //定义onBinder方法的返回的对象
    private MyBinder binder = new MyBinder();
    //通过继承Binder来实现IBinder类
    public class MyBinder extends Binder{

        public int getCount(){
            //获取Service的运行状态:count
            return count;
        }
    }

    //必须实现的方法
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("Service is Binded");
        //返回IBinder对象
        return binder;
    }

    //Service被创建时回调该方法
    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("Service is Created");
        //启动一条线程、动态地修改count状态值
        new Thread(){

            @Override
            public void run() {
                super.run();
                while (!quit){
                    try{
                        Thread.sleep(1000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        }.start();
    }

    //Service被断开连接时回调该方法
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("Service is Unbinded");
        return true;
    }

    //Service被关闭之前回调
    @Override
    public void onDestroy() {
        super.onDestroy();
        this.quit = true;
        System.out.println("Service is Destroyed");
    }
}

定义Activity来绑定Service。

public class Activity26 extends BaseActivity {

    Button bind, unbind, getServiceStatus;
    //保存所启动的Service的IBinder对象
    BindService.MyBinder binder;
    //定义一个ServiceConnection对象
    private ServiceConnection conn = new ServiceConnection() {
        //当该Activity与Service连接成功时回调该方法
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            System.out.println("--Service Connected--");
            //获取Service的onBind方法返回的MyBinder对象
            binder = (BindService.MyBinder) iBinder;
        }
        //当该Activity与Service断开连接时回调该方法
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            System.out.println("--Service Disconnected--");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity26);
        bind = findViewById(R.id.bind);
        unbind = findViewById(R.id.unbind);
        getServiceStatus = findViewById(R.id.getServiceStatus);
        final Intent intent = new Intent(context, BindService.class);
        bind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //绑定指定Service
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
        });
        unbind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //解绑Service
                unbindService(conn);
            }
        });
        getServiceStatus.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //获取并显示Service的count值
                Toast.makeText(context, "Service的count值为:" + binder.getCount(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}
Service生命周期

两种启动方式Service生命周期如下图:


通过startService()方法启动Service的生命周期
通过bindService()启动的Service的生命周期
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355