这篇文章主要介绍android中的service
首先我们要弄清楚service到底是什么东西,它是android用于提供后台服务的,注意service(IntentService)不是进程,也不是线程,是依赖于应用程序的主线程的。Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。我们在使用service的时候,一般使用要在其内部开启一个线程来处理操作,同时我们也要注意,不要在service里面处理耗时操作,否则会引起ANR
但是service也有它的用处,拥有service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
1. 如果service
正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
2. 如果当
前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3. 如果
客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。
4. 如果
service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。
接下来我们先来创建一个简单service,需要继承service这个抽象类
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
/**
* 在服务创建是调用
*/
@Override
public void onCreate() {
super.onCreate();
}
/**
* 在每次服务启动时调用
* 如果我们希望服务一旦启动就去执行这个动作,就可以在这里实现
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
/**
* 在onStartCommand后调用
*/
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
}
/**
* 服务销毁时调用,用于回收资源
*/
@Override
public void onDestroy() {
super.onDestroy();
}
/**
* 抽象方法,必须实现
*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
然后我们在AndroidManifest.xml文件里面进行注册
,我们应该注意到
android的四大组件,都必须在AndroidManifest.xml文件里面注册才生效
<service android:name=".Myservice"></service>
接下来是在Activity启动和停止服务,其实过程和启动Activity类似,另外还有一个关闭
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MyActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//启动service
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);
//关闭service
Intent stopIntent = new Intent(this,MyService.class);
stopService(startIntent);
}
}
另外在service中,我还有调用
stopSelf()方法
让服务自己停下来,
另外无论启动了多少次service,都只有一个service实例,所以只要关闭一次就可以了
这里要注意onCreate()和onStartCommand()的执行时间问题,当我们第一次创建服务时,这两个方法都会调用,以后我们启动服务,就不会在调用oncreate方法了,而是直接调用onStartCommand(),它的本质是调用了onStart()方法
接下来要说service跟activty的通信问题
要使用通信,必须使用另外一种启动service的方法
//绑定并启动service
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE);
与startService()方法类似,bindService()方法启动以后,会依次调用onCreate方法和
onBind方法
此后,如果再次使用bindService绑定服务,系统不会创建新的Service实例,也不会再调用onBind方法;
如果我们需要解除与这个服务的绑定,可使用unbindService方法,此时onUnbind方法和onDestroy方法会被调用。
这里要说一下startService()方法与bindService()方法的不同:
startService模式下调用者与服务无必然联系,即使调用者结束了自己的生命周期,只要没有使用stopService方法停止这个服务,服务仍会运行;
通常情况下,bindService模式下服务是与调用者生死与共的,在绑定结束之后,一旦调用者被销毁,服务也就立即终止,所以一旦要在activty的finish之前解除绑定!
通信过程如下:
bindService()中传入一个ServiceConnection,这个ServiceConnection有两个方法分别在service绑定与解绑定的时候调用,在绑定方法中,我们可以获得service里面的binder对象(由service的onBinder()方法提供),这样activity就知道了来自service的信息了。注意IBinder是一个接口,Binder是一个实现IBinder的类
这里onBind()方法返回的IBinder对象,相当于Service的代理,Activity通过这个代理来访问Service的数据
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class MyService extends Service {
private MyIBinder myIBinder = new MyIBinder();
class MyIBinder extends Binder{
//这里提供一些接口函数
};
/**
* 抽象方法,必须实现
*/
@Override
public IBinder onBind(Intent intent) {
return myIBinder;
}
/**
* 程序调用unbindService()以后调用
* 之后才执行destory()
*/
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
}
在activty里面:
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
public class MyActivity extends Activity{
ServiceConnection connection = new ServiceConnection() {
/**
* 解除绑定
*/
@Override
public void onServiceDisconnected(ComponentName name) {
}
/**
* 绑定服务
* IBinder就是对于服务onBind()方法返回的对象
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//可以调用IBinder的方法了,也就是实现通信
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//绑定并启动service
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_AUTO_CREATE);
}
}
要解除绑定的话,在activty调用
//解除绑定
unbindService(connection);
即可,调用以后,会先触发onUnbind()方法,然后在触发onDestory()方法
另外还有提一句:onServiceDisconnected(ComponentName name)方法只有在service所在的宿主进程由于异常中止或者其他原因终止,导致该Service与访问者之间的连接断开时才会调用,而主动调用unBindService()方法断开service连接,是不会调用onServiceDisconnected(ComponentName name)方法的
综上所述有两种启动service的方法,但是如果我们两个都调用了,会出现什么情况呢?
要解决这个问题,我们先来看一下有两种方法启动的service生命周期
除了上述情况以外,我们再假设一种情况:
假设service先后调用了startService(),bindService(),在调用了unbindService,最后又调用了bindService()
这个过程生命周期如下:
onCreate()->onStartCommand()->onBind()->onUnbind()[重写改方法时返回true]->onRebind()
我们可以注意到,重新绑定时会调用onRebind()方法,但是前提是onUnbind()方法返回true
另外这个过程,没有调用ondestory()方法,因为Service不是由bindService()方法启动的,所以我们要调用stopService()才能停止改service
根据android系统的机制,一个服务只要被启动或者绑定以后,就会一直处于运行状态,必须让以上两种条件都不满足服务才能被销毁。上述情况,既要调用stopService()也要调用unbindService(),这样onDestory()方法才会执行
上述内容已经说明了service的基本使用,因为service的操作实际是在主线程执行的,为了避免阻塞,所以我们往往在service创建子线程
常见写法:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 开始执行后台任务
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// 执行具体的下载任务
}
}).start();
}
}