android之Service(1)Started Service

Service是Android四大组件之一,常用于后台处理耗时任务。本文介绍了如何启动和停止Service,重点讲解了onStartCommand方法,包括START_STICKY、START_NOT_STICKY和START_REDELIVER_INTENT三种返回值的含义,并强调了Service生命周期的管理,特别是在内存不足时的行为。
摘要由CSDN通过智能技术生成

简介

Service(服务)作为Android四大组件之一,在应用程序中扮演着非常重要的角色,不能自己运行只在后台运行,可以和其它组件进行交互。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。总之Service是藏在后台的
启动服务有两种方式,本章先介绍Started方式。

启动/停止Service

首先给出官方提供的Service生命周期图(后续详细分析1,这里简单介绍。)
service_lifecycle
上图中的左半部分即为Started方式启动Service的生命周期,具体启动/停止Service步骤如下:

  1. 创建一个类继承android.app.Service类,重写onCreate(),onStartCommand()onDestroy()三个方法。
  2. 在AndroidManifest.xml文件中声明Service。
  3. 在Activity中,通过Intent对象设置要启动的Service,调用Context类中的startService()方法启动。
  4. 调用Context类中的stopService()方法停止Service(另一种方式下面讲)。

代码如下:
MyService类代码:

package com.sywyg.servicetest;

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

/**
 * 自定义Service类
 * @author sywyg
 * @since 2015/4/30
 */
public class MyService extends Service {

    public MyService() {
    }
    /**
     *Service第一次被创建时调用
    */
    @Override
    public void onCreate(){
        super.onCreate();
        Log.d("MyService","onCreate...");
    }

    /**
     *每次启动服务时调用,Service需执行的业务逻辑写在这里。后续详解
     * @param intent对应启动时的intent
     * @param flags对应返回值类型
     * @param startId Service的启动标识,识别第几次
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService","onStartCommand...");
        Log.d("MyService",intent.getStringExtra("name"));
        return super.onStartCommand(intent, flags, startId);
    }
    /**
     *Service被销毁时调用,该方法通常用于回收系统资源
    */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService","onDestroy...");
    }

    /**
     * 抽象方法,Started方式中用不到
     * @param intent
     * @return
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

  • 无参构造器必须有。
  • Service需在AndroidManifast.xml中注册才能生效。

Acitvity中代码如下:

package com.sywyg.servicetest;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;

/**
 * Started方式启动Service
 * @author sywyg
 * @since 2015/4/30
 */

public class MainActivity extends ActionBarActivity implements View.OnClickListener{
    private Button btn_started;
    private Button btn_stop;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_started = (Button)findViewById(R.id.btn_started);
        btn_stop = (Button)findViewById(R.id.btn_stop);
        btn_started.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
    }
//主要实现代码
    @Override
    public void onClick(View v) {
        Intent intent;
        switch(v.getId()){
            case R.id.btn_started:
                //启动Service
                intent = new Intent(this,MyService.class);
                intent.putExtra("name","sywyg");
                startService(intent);
                break;
            case R.id.btn_stop:
                //关闭Service
                intent = new Intent(this,MyService.class);
                stopService(intent);
        }
    }
}

运行程序并点击启动服务按钮,LogCat的打印日志如下:

这里写图片描述

当启动一个Service时会调用该Service中的onCreate()onStartCommand()。同时可以看到参数intent可以获取Activity中Intent对象添加的扩展信息。如果再点击启动服务按钮按钮的话,LogCat的打印日志如下:
这里写图片描述

这次只有onStartCommand()方法执行了,onCreate()方法并没有执行。
这是由于onCreate()方法只会在Service对象第一次被创建的时候调用,这说明Service对象只能有一个。

点击停止服务按钮,就会执行onDestroy()方法。

注:

  • 默认情况下,一个started的Service与启动它的组件在同一个线程中,若Service需要完成一些耗时的工作,则就会阻塞该线程,因此我们必须使用新的线程来处理该工作(在onStartCommand()方法中新建线程或通过IntentService)。

onStartCommand详解

onStartCommand()方法代替了原来的onStart()方法(已被弃用),一般在这实现服务执行的操作,共有三个参数:
这里写图片描述

  • intent
    对应启动时的intent,通过该参数可以获取调用该Intent对象设置的信息,如:获取附加信息等。
  • flags
    启动服务的方式(判断onStartCommand()的返回值),默认情况下是0,其它取值,官方文档是这样介绍的:
    flags
    参数flags默认情况下是0。START_FLAG_REDELIVERY:表示该方法返回值设为START_REDELIVER_INTENT,则会被传入这个标记。START_FLAG_RETRY:表示该方法返回值设为START_STICKY,则会被传入这个标记。
  • startId
    startId表示当前启动的Service的次数。startId是一个唯一的整型,用于表示此次用户执行startService()的请求标识,在多次请求startService()的情况下,呈现1,2….递增。 在stopselfResult(int)方法中的int值即为该值。

onStartCommand()方法返回一个int类型,有下列3种(START_STICKY_COMPATIBILITY已被弃用?)取值:
这里写图片描述

  1. START_STICKY
    当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand()方法,但其中的Intent将是null,pendingintent除外。
  2. START_NOT_STICKY
    当Service因为内存不足而被系统kill后(保留Service为开始状态,不保留传递的intent对象),接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中用户明确再次调用startService()启动此Service。

  3. START_REDELIVER_INTENT
    与START_STICKY唯一不同的是,回调onStartCommand()方法时,其中的Intent对象非空,将是最后一次调用startService()的intent。

以上的描述中,”当Service因为内存不足而被系统kill后“(还是被系统异常kill)一定要非常注意,因为此方法的返回值设定只是针对此种情况才有意义的,换言之,当人为的kill掉Service,此方法返回值无论怎么设定,接下来未来的某个时间内,即使系统内存足够可用,Service也不会重启。

以上返回值暂未验证。

停止Service

一个启动的服务必须管理自己的生命周期,除非系统需要回收资源,否则系统不会停止或者销毁服务。因此服务必须通过调用Service类的stopSelf()(无参)来停止自己,或者其他组件调用Context类的stopService()。
一担收到stopSelf()或stopService()的停止请求,系统会立刻销毁服务(调用onDestroy()方法)。
如果你的服务同时处理多个服务请求,当某个请求完成时就不能马上停止服务,因为你可能已经又接受了一个新的请求(在第一个请求完成时结束服务会终止第二个请求)。为了解决这个问题,你可以调用stopSelf(int)方法或stopSelfResult(int)(返回boolean,前一个没有返回值)来保证你的停止请求总是基于最近的一次服务请求。这是因为,用stopSelf(int)方法会把onStartCommand()方法传入的startId传给停止请求。当你的startId和最近一次接受的服务请求不匹配时,服务不会结束。当然你也可以随便设置传入的int值。

  1. stopSelf(int)方法只是简单的与最近一次收到的startId比较,如果你的服务处理过程是多线程的,可能后收到的服务请求先完成,那stopSelf(int)的方案不适合,你应该手动管理接受到的服务请求和完成的服务,比如在onStartCommand()方法中把startId记录到一个表中,在完成服务任务时在表中记录完成状态,在确保表中任务都完成的情况下直接调用stopSelf()方法来停止服务。
  2. 默认情况下,服务和启动该服务的组件在同一线程(主线程)被调用。通常服务不能在主线程被调用,若服务不结束则会阻塞该组件,例如按钮上不来了。可以通过新线程管理Service。也可以用IntentService来实现Service类,见2

http://blog.csdn.net/huangbiao86/article/details/7035920
http://www.cnblogs.com/lwbqqyumidi/p/4181185.html
http://blog.csdn.net/guolin_blog/article/details/11952435

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值