1,Service的基本概念;
2,Service的生命周期;
3,进程生命周期;
Service概述:
Service是Android中非常重要的组件之一。它和Activity很相似,都代表可执行的程序。但是他们的区别在于,Service一直运行在后台,它没有用户界面,无法与用户交互。Service启动后,和Activity一样有自己的生命周期。使用Service的方法和Activity也相似,每创建一个Service的子类就需要在Manifest.xml文件中有对其的声明(<service>标签),当然它也能够使用<intent-filter>标签设置intent的过滤条件。需要注意的是:Service和其他应用组件一样运行在它宿主的主线程中(也叫UI线程)。当我们要在Service中执行耗时的操作时,我们应该将这些操作放在另外的线程中。
关于Service我们需要明确几点:
1,Service组件并不是运行在自己的进程中,除非我们另外指定,它运行在和应用相同的进程中;
2,一个Service开启并不是说它就开启了一个线程,它没有脱离主线程(但是我们通常在做耗时操作时这样做,为了防止发生Android Not Responsing);
Service实际上是一个很简便的组件,提供了一些很重要的特性:
1,使用Service,相当于告诉系统我们要做一些后台的操作,这些操作不需要和用户直接进行交互。
2,Service也提供了和其他应用程序通信的途径
Service的生命周期:
Service可以有两种方式启动,通过startService()或者bindService()。不同的启动方式他们的生命周期也有一些不同。通过startService()启动时生命周期如左图(这个时候会调用onStartCommand()方法,如果希望Service组件做些什么事情的话可以在onCreate()、onStartCommand()中定义相关的业务代码就可以了),通过bindService()启动时生命周期如右图(这种方式提供了Service和本地通信/和其他应用程序通信的途径,以后会涉及到)。startService()启动指定的Service:第一次启动Service时会调用onCreate()方法,接着调用onStartCommand(),这时service开始运行,直到调用stopService()或者stopSelf()方法。这里如果多次的调用startService()来启动service,并不会重新调用onCreate()方法多次,但是onStartCommand()方法会调用多次,同样也只需要一次stopService()或者stopSelf()就可以停止Service。这种方式启动的Service时,根据onStartCommand()的返回值不同,有着不同的工作模式:
START_STICKY:表示Service在任何时候都是明确的开启和停止,例如:在后台播放音乐;(如果这个Service的进程在onStartCommand()返回后被杀死,这个Service会停留在启动状态,但是系统并不会保留那个Intent,而是会在稍后的时间内尝试重新创建这个Service,并且会调用onStartCommand。如果没有任何启动的命令传递到这个Service,那么就会传递一个为null的Intent。)
START_NOT_STICKY:表示这个Service不需要一直保持运行状态,只是在接收到运行命令后才开始工作,例如:数据库的查询;(如果这个Service的进程在onStartCommand()返回后被杀死,并且没有新的启动Intent发送过来,这时Service就会离开启动状态,系统不会重新创建它,直到有明确的启动操作startService()出现。)
START_REDELIVER_INTENT:和START_NOT_STICKY类似。(如果这个Service的进程在onStartCommand()返回后被杀死,它会重新启动并且最后一次通过onStartCommand()传递过来的Intent会被重新传递过来,并且这个Intent会一直重传直到服务被stop)
bindService()启动Service:可以建立客户端和Service的连接,但是不会调用 onStartCommand()方法。客户端会接收到一个onBind()方法返回的IBunder对象,这样就允许客户端回调到Service。Service会一直保持运状态,只要这个连接没有断。(通常这个IBinder会比较复杂,在实现进程间通信的时候,它可以是一个AIDL的接口)这些知识会在后面涉及到,这里不做详解。
Service生命周期还有一种较特殊的情形:如果Service已经由一个Activity通过startService()启动,接下来其他Activity又通过bindService()来绑定该Service,再调用unbindService()来解除绑定,最后又调用bindService()再次绑定它,这个时候出发的生命周期是:
onCreate()——>onStartCommand()——>onBind()——>onUnBind()[重写该方法时返回true]——>onReBind()可看到Service的onReBind()方法被回调,这是不仅需要Service是由startService()启动的,还需要重写onUnBind()时返回true。
例子:
布局只有简单的四个按钮:
Activity作为启动Service的客户端:
package com.flyingduck.servicedemo;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ClientActivity extends Activity {
private Button startBtn;
private Button bindBtn;
private Button unBindBtn;
private Button stopBtn;
// bindServier()用到
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
startBtn = (Button) findViewById(R.id.start_service);
bindBtn = (Button) findViewById(R.id.bind_service);
unBindBtn = (Button) findViewById(R.id.unbind_service);
stopBtn = (Button) findViewById(R.id.stop_service);
final Intent intent = new Intent(getApplicationContext(),
ServiceDemo.class);
conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
}
};
// 通过startService()启动Service
startBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
startService(intent);
}
});
// 通过bindService()绑定service
bindBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
});
// 解除绑定
unBindBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
unbindService(conn);
}
});
// 停止service
stopBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);
}
});
}
}
service:
package com.flyingduck.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class ServiceDemo extends Service {
private static String TAG = "service demo";
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind...!");
return null;
}
@Override
public void onCreate() {
Log.i(TAG, "onCreate...!");
super.onCreate();
}
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy...!");
super.onDestroy();
}
@Override
public void onRebind(Intent intent) {
Log.i(TAG, "onRebind...!");
super.onRebind(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand...!");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind...!");
return true;
}
}
Manifest.xml千万不能忘记配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.flyingduck.servicedemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.flyingduck.servicedemo.ClientActivity"
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="com.flyingduck.servicedemo.ServiceDemo" >
</service>
</application>
</manifest>
运行截图:
依次点击:StartService、BindService、UnBindService、BindService按钮:
结果如下:
这种情形下并不会回调Service的OnDestroy()方法,这是因为该方法并不是由Activity通过bindService()来启动的(是由startService()启动的),因此即使调用Service的unBindService()方法解除与Service的绑定,该Service也不会终止。
由此可见,当Activity调用bindService()绑定一个已经启动的Service时,系统只是把Service内部的IBinder对象传给了Activity,并不会把该Service生命周期完全绑定到Activity。因此,在调用unBindService()取消与该Service的绑定时,也只是切断了Activity与Service的联系,并不能停止Service组件。
进程生命周期
只要Service被启动或者被绑定到宿主进程上,Android系统就会让这个进程一直持有这个Service。当系统内存不足或者其他情况需要杀死一些存在的进程时,持有Service的进程在一下这些情况下会有较高的优先级:
1,当service正在执行声明周期中方法(onCreate()、onStartCommand()、onDestroy()),宿主进程会成为前台进程来保证service正常的执行;
2,当Service启动后,宿主进程会的优先级别会 < 当前正在和用户交互的进程,>其他不可见的进程;
3,如果有很多客户端绑定到了service,那么这个service的宿主进程的有限级别高于优先级最高的那个客户端。也就是说,如果客户端中的一个是对用户可见的,那么这个Service可以被看作是可见的;
4,当Service通过startForeground()启动,进入前台状态,那么在系统内存低的情况下,不会被杀死。
在Service运行的大部分时候,系统都可能在内存不足的情况下杀死service。Service被杀死后系统会在之后尝试重新启动这个Service。所以,在我们重写onStartCommand()去做一些事情,并且我们是在异步操作或者在一个新的线程中去做这些事情的话,我们做好使用START_FLAG_REDELIVERY让系统重传一个intent,以免造成不必要的损失。