在手机管理中经常看到进程和服务,进程指的就是App应用在运行,服务就是Android四大组件之一的Service。
Service是一个具有较长生命周期但没有用户界面的组件,说它生命周期长并不是它运行中回调的方法多,而是它可以存在很长时间,如果必要可以一直运行,没有用户界面就是看不到,无法与用户进行交互,如果不以特殊的方式表现它的状态是无法获知它的存在的。Android手机中诸如后台下载、音乐后台播放、GPS定位服务等等都是服务的,正因为它的特性我们通常在Service中执行相对耗时的操作。
创建一个Service就不如Activity那样方便了,自定义Service需要手动继承Service类,配置文件也需要手动配置。对于一些系统级的Service可以直接通过getResource()方法来获取(这是因为Activity和Service都是Context的派生类)。
Service的配置与Activity类似,在<service>标签内必须配置name属性,同时也可以配置<intent-filter>为Service设定<action>等标记元素来完成隐式Intent的调用。
Service的启动需要依赖其他组件,可以使用Activity或者Receiver等作为调用者,启动方式分为startService启动和bindService绑定两种,这两种方法启动的Service拥有不同的生命周期。
startService启动的Service生命周期与Activity没有关联,即使Activity被销毁Service依然运行
onCreate()创建Service实例时的回调函数
onStartCommand()启动Service时的回调函数
onDestory()销毁Service时回调,Service一旦启动无法自动终止,除非手动停止stopService或者卸载应用程序
关于onStartCommand()返回参数onStartCommand(intent, flags,startId),startId可以获取Service被启动的次数,flags是用来指定Service的系统在用户为手动关闭Service前自动回收Service资源了Service资源情况下的重启行为,它有以下值
START_STICKY
“粘性的”。如果Service进程被kill掉,保留Service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建Service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY
“非粘性的”。如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT
如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:
START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
bindService启动的Service生命周期受到调用者的影响,如果调用者被销毁,Service也会被销毁。
bindService(Intent service,ServiceConnection conn, int flags)
service要绑定Service信息的Intent对象
conn监听访问者与Service之间的连接情况。当访问者与Service之间链接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName,IBinder)方法;当Service所在的宿主进程由于异常中止或由于其他原因终止,导致该Service与访问者之间断开连接时回调该ServiceConnection对象的onServiceDisconnected(ComponentName)方法。其中onServiceConnected方法中的IBinder对象,可实现与被绑定Service之间的通信。在开发Service类时,该Service类必须提供一个IBinder onBind()方法,该方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected方法的参数中。这样访问者就
可以通过该IBinder对象与Service进行通信。实际开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。
flags指定绑定时是否自动创建Service (如果Service还未创建),该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)。
onCreate()同startService
onBind()在Service与调用者建立关联关系时使用,该方法会返回一个IBinder类型的实例给调用者,作为Service在调用者的代理
onUnbind() Service与调用者解除绑定
onDestory()同startService
以下针对Service的使用和生命周期做一个简单的测试,首先,我们分别通过两种方式启动Service,其次在两个Service中都进行线程计数,做一些简单的实验,布局文件如下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.briup.service.MainActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="startService"
android:text="StartService" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="stopService"
android:text="StopService" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="bindService"
android:text="BindService" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="unBindService"
android:text="UnBindService" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="getcount"
android:text="getCount" />
</LinearLayout>
MainActivity类文件如下
import com.briup.service.SecondService.MyBinder;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
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.widget.Toast;
public class MainActivity extends Activity {
private ServiceConnection conn;
private final static String TAG = "briup";
private MyBinder binder;//在SecondService服务中自定义的Binder类
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
conn = new ServiceConnection() {
// 在Activity与Service异常解除绑定时回调
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MainActivity-onServiceDisconnected");
}
// 在Activity与Service进行绑定成功时回调
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "MainActivity-onServiceConnected");
binder = (MyBinder) service;//通过IBinder对象和自定义的Binder类实现数据传递
}
};
}
public void startService(View v) {
Intent intent = new Intent(this, FirstService.class);
// 通过start启动的服务,该服务的生命周期与Activity没有任何关联
startService(intent);// 启动服务
}
public void stopService(View v) {
Intent intent = new Intent(this, FirstService.class);
stopService(intent);// 终止服务
}
public void bindService(View v) {
Intent intent = new Intent(this, SecondService.class);
// 通过绑定方式启动服务,调用者的生命周期会影响服务的生命周期
bindService(intent, conn, Service.BIND_AUTO_CREATE);// 绑定服务
}
public void unBindService(View v) {
unbindService(conn);// 解绑服务
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(conn!=null)
unbindService(conn);// 需要在调用者的Destroy方法中进行解绑,否则强退出错(当然前提是绑定了服务,否则会因为找不到服务而无法退出Activity终止程序)
}
public void getcount(View v) {//获取服务数据
Toast.makeText(this, binder.getCount() + "", Toast.LENGTH_LONG).show();//调用自定义的Binder类中的方法完成数据传递
}
public void startIntentService(View v) {
Intent intent = new Intent(this, MyIntentService.class);
startService(intent);
}
}
FirstService类文件如下
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class FirstService extends Service{
private int count = 1;
private final static String TAG = "briup";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.i(TAG, "FirstService onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i(TAG, "FirstService onStartCommand");
new Thread(){
public void run(){//通过创建子线程做计数
while(count<101){
Log.i(TAG, "count:"+count);
try {
sleep(500);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
count=200;//手动设置计数为200跳过循环即可终止线程
Log.i(TAG, "FirstService onDestroy");
}
}
SecondService类文件如下
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class SecondService extends Service {
private final static String TAG = "briup";
private int count = 1;
// 通常自己写一个类继承Binder,也就间接的实现了IBinder接口
public class MyBinder extends Binder {
public int getCount() {
return count;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i(TAG, "SecondService onBind");
new Thread() {
public void run() {
while (count < 101) {
Log.i(TAG, "count:" + count);
try {
sleep(500);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
return new MyBinder();
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.i(TAG, "SecondService onCreate");
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
Log.i(TAG, "SecondService onUnbind");
count = 200;
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.i(TAG, "SecondService onDestroy");
super.onDestroy();
}
}
配置文件如下
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.briup.service"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".FirstService"
></service>
<service
android:name=".SecondService"
></service>
<service
android:name=".MyIntentService"
></service>
</application>
</manifest>
效果如下
startService后不论按HOME键还是退出Activity都在计数运行
stopService后计数即停止
bindService
unbindService和退出Activity的情况相同,至于那种异常解绑需要异常时出现
getCount
Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,那么如果主线程被终止或阻塞,就会引起ANR(Application Not Responding,程序无响应)。我们推荐编写耗时程序时使用IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部自己开了一个线程,可以用来执行耗时操作。该线程保证同一时刻只处理一个Intent,这样IntentService不会阻塞主线程。
IntentService的使用和Service是类似,需要重写onHandleIntent(Intent intent)方法,以下代码实现与上面功能相同的Service,不需要创建依赖于主线程的子线程。
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class MyIntentService extends IntentService {
private int count = 1;
private final static String TAG = "briup";
public MyIntentService(String name) {
super(name);
// TODO Auto-generated constructor stub
}
public MyIntentService() {// 要求创建一个无参构造器,并且必须传一个名字,否则报错
super("MyIntentService");
}
@Override
// 重写该方法不需要创建子线程,该方法提供新开的线程供耗时操作
protected void onHandleIntent(Intent intent) {
while (count < 101) {
Log.i(TAG, "count:" + count);
try {
Thread.sleep(500);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}