简介
Service(服务)作为Android四大组件之一,在应用程序中扮演着非常重要的角色,不能自己运行只在后台运行,可以和其它组件进行交互。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。总之Service是藏在后台的
启动服务有两种方式,本章先介绍Started方式。
启动/停止Service
首先给出官方提供的Service生命周期图(后续详细分析1,这里简单介绍。)
上图中的左半部分即为Started方式启动Service的生命周期,具体启动/停止Service步骤如下:
- 创建一个类继承android.app.Service类,重写
onCreate()
,onStartCommand()
和onDestroy()
三个方法。 - 在AndroidManifest.xml文件中声明Service。
- 在Activity中,通过Intent对象设置要启动的Service,调用Context类中的
startService()
方法启动。 - 调用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默认情况下是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已被弃用?)取值:
- START_STICKY
当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand()
方法,但其中的Intent将是null,pendingintent除外。 START_NOT_STICKY
当Service因为内存不足而被系统kill后(保留Service为开始状态,不保留传递的intent对象),接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中用户明确再次调用startService()启动此Service。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值。
注
stopSelf(int)
方法只是简单的与最近一次收到的startId比较,如果你的服务处理过程是多线程的,可能后收到的服务请求先完成,那stopSelf(int)
的方案不适合,你应该手动管理接受到的服务请求和完成的服务,比如在onStartCommand()
方法中把startId记录到一个表中,在完成服务任务时在表中记录完成状态,在确保表中任务都完成的情况下直接调用stopSelf()
方法来停止服务。- 默认情况下,服务和启动该服务的组件在同一线程(主线程)被调用。通常服务不能在主线程被调用,若服务不结束则会阻塞该组件,例如按钮上不来了。可以通过新线程管理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