您的位置:首页 > 其它

Service

2015-08-15 22:12 381 查看
/article/8182960.html

本文出自:【yujun411522的博客】

两种方式:start和bind。
1.start方式:android 中其他组件可以调用startService(Intent) 方式来启动一个service。如果该service实例不存在,则调用service.oncreate()方法实例化,再调用onStartCommand方法来处理该Intent操作。启动service之后,该service实例就独立于启动它的组件,可以在后台永远的运行下去,甚至是启动它的组件被destory。onstartCommand返回值是一个整形,表示如果系统杀死该service之后应该如何操作。返回值必须是
START_NOT_STICKY,START_STICKY,START_REDELIVER_INTENT。三个标志代表service被杀死后该service的一些处理:
START_STICKY:重新创建service,然后调用onStartCommand方法,但是不会redeliver最后一次的intent,onStartCommand传递的是null。适用于不执行命令,一直运行等待一个工作的service。
START_NOT_STICKY:不重新建立service。除非有pendingIntent。
START_REDELIVER_INTENT:不仅重新建立service,且将最后的intent redeliver给service。适用于需要立马重新恢复的工作,下载文件。
如果是start方式启动service,service没有结束之前,无论调用多少次startService,系统中就只有这一个service实例。如果想关闭service可以使用stopService方法。如果service停止,系统调用service的onDestory方法,所以在ondestory方法中可以释放资源(网络,mediaplayer)。多次startservice会导致多次执行onStartCommand,但是只要有一个stopService,就会停止service。这里推荐使用stopself(int
startid)。如果startid是最新的请求id,则会停止服务,否则不会停止service。
使用start这种方式一般执行一个单一操作,不能和启动它的组件交互。所以出现了第二种方式:bindService
2.bind方式:提供一种Client-Server架构方式,启动组件可以和service进行交互。其中最重要的是public IBinder onBind(),返回一个IBinder对象(基础binder类即可)。然后在bindService(intent,serverConection,flag)中连接。如下:
1.继承Service类,并实现onBinder方法,返回一个Binder对象。

[java]
view plaincopyprint?

public IBinder onBind(){ // return binder; } class MyBinder extends Binder{ //提供的操作 }

public IBinder onBind(){
//
return binder;
}
class MyBinder extends Binder{
//提供的操作
}

2.clinet调用bindService(Intent,ServiceConnection,int)。主要是提供一个serviceconnection类。

[java]
view plaincopyprint?

ServiceConnection connection = new ServiceConnection(Component){ //与service连接失败 public void onServiceDisconnected(){ //当connection异常结束,如果service崩溃、被杀死时。注意,此方法不会在unbind时执行。 } //与service连接成功 public void onServiceConnected(ComponentName,IBinder){ //当成功返回service中onBind方法中的IBinder对象时调用 MyBinder binder= (MyBinder)service; //得到service的binder,然后进行操作 } }

ServiceConnection connection = new ServiceConnection(Component){
//与service连接失败
public void onServiceDisconnected(){
//当connection异常结束,如果service崩溃、被杀死时。注意,此方法不会在unbind时执行。
}
//与service连接成功
public void onServiceConnected(ComponentName,IBinder){
//当成功返回service中onBind方法中的IBinder对象时调用
MyBinder binder= (MyBinder)service;
//得到service的binder,然后进行操作
}
}

执行bindService之后,立刻返回,等待执行service的onBind方法,然后触发serviceConnection的相应操作。
注意,同一组件多次调用bindService时只有第一次有效,之后既不会执行onBind方法,也不会触发ServiceConnection中操作(已经建立好了连接了);而对于不同组件调用bindService方法,只有第一次bind时,service才会执行onBind检索IBinder对象,当其他client
bind时,直接返回该IBinder对象,不再执行onBind方法。
如果不再需要bindService之后,通过unbindService来解除绑定。这时会触发service的onUnbind方法。只有当所有的client都解除绑定之后,service才会销毁。如果client被destory,那么也会调用service的unbind(比如Activity被destroy之后它所绑定的service就unbind了),所以最好在不需要交互service之后立马主动解除绑定。

3.1 Service生命周期
Service是一个可以长期运行在后台的组件,它并不提供一个界面。都是其他组件通过startservice或者bindservice来启动或者绑定它。
创建一个service要继承Service类,该类中有几个重要的方法。
1.onCreate():当service第一个创建时调用,该方法在onStartCommand和onBind之前调用,且只会调用一次。如果service已经创建过就不会调用此方法。
2.onStartCommand():当其他组件调用startService发送一个请求时,service调用此方法处理该请求。一旦开始执行此方法,service可以长期运行在后台之中,所以有必要在不需要服务的时候停止服务(自己调用stopSelf或者其他组件调用stopService)。
3.onBind():当其他组件调用bindService时service调用onBind方法(unbindService或者绑定组件生命结束)。
通过stopService方式和通过bindService方式启动的Service生命周期有所不同



至于既startservice又bindService的则比较复杂,上图:



3.3 Service和线程的关系
要注意一点,默认情况下service仍然是运行在UI线程中,并没有启动一个新线程来处理任务。如果在service中处理过于耗时的操作仍然会导致ANR,这时需要新开启一个线程来处理。Service的目的是长期运行在后台,不依赖于UI界面。也就是即使是UI被销毁了,service依然是运行的。
也就是说我们在创建一个Service时,该service是运行在主线程之中的,并没有创建一个子线程运行这个service。
为什么不在Activity中使用线程操作?这是由于Activity本身的生命周期和作用决定的,Activity的生命周期可能很短,一旦back之后就结束了。那么Activity所管理的线程就不好控制。再者来说Activity的目的本来就是作为用户界面,用户界面不能有太多的操作。但是Service就不一样,如果不主动stopService的话,service就一直在运行,只要能startService或者bindService就可以建立起与对应子线程的联系。
使用service还有一个好处就是只要是能和service关联上就可以操作它。假如在Activity中开启一个线程,Activity一旦destroy就无法控制该线程,才做起来很不方便;而使用service,只要service没有结束,即使是Activity被destroy,仍然可以与service建立关系管理线程

3.4 IntentService
上面说过service仍然是运行在UI主线程中,需要自己来开启线程处理耗时工作。Android系统提供了一个集成子线程的IntentService类来帮助我们。
IntentService 使用场景:一项任务有几项子任务,每一项子任务先后顺序执行,只有所有的子任务都执行完了,任务才完成。
client仍然通过startService发送请求,IntentService使用一个新的worker thread 按照请求顺序处理请求,当所有任务执行完毕之后通知IntentService。所有的请求都是通过一个worker thread来处理的,而且每次处理一次,按照请求顺序
IntentService做了以下工作:
1.oncreate方法中创建了一个worker thread。该thread和UI线程分开,用来单独处理request

[java]
view plaincopyprint?

@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.

super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//工作线程名称
thread.start();

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.

super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//工作线程名称
thread.start();

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}


2.onStart方法中将请求加入消息队列,然后不断从消息队列中去消息执行onHandleIntent和stopSelf方法。

[java]
view plaincopyprint?

@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);//利用handler 和message进行通信
}

@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);//利用handler 和message进行通信
}


3 对应的mServiceHandler的消息处理函数:

[java]
view plaincopyprint?

private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//调用onHandleIntent方法
stopSelf(msg.arg1);
}
}

private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);//调用onHandleIntent方法
stopSelf(msg.arg1);
}
}

显然是调用了onHandleIntent方法和stopSelf方法。而onHandlIntent是一个抽象方法,我们需要实现它。
这里简要说一下stopSelf方法,如果参数是最新startID,那么service调用ondestory方法。所以即使是当前处理的message不是最后一个请求,service仍然不会被关闭。直到处理最新的一个请求完毕才stopservice。
在自己继承IntentService时,有两个方法必须提供,一个是构造方法,一个是onHandleIntent
构造方法:

[java]
view plaincopyprint?

public MyIntentService(){
//为工作线程提供一个name
super("worker thread name");
}
@Override
protected void onHandleIntent(Intent intent) {
Log. d( TAG, "onHandleIntent,thread id:"+Thread.currentThread ().getId());
Log. d( TAG, "onHandleIntent,intent:" +intent.toString());
}

public MyIntentService(){
//为工作线程提供一个name
super("worker thread name");
}
@Override
protected void onHandleIntent(Intent intent) {
Log. d( TAG, "onHandleIntent,thread id:"+Thread.currentThread ().getId());
Log. d( TAG, "onHandleIntent,intent:" +intent.toString());
}

执行完onHandleIntent之后,如果没有其他的请求,自己立即调用stopSelf,终止service



同时可以看出,在onHandleIntent是在子线程中处理的。
下面模拟多个请求:

[java]
view plaincopyprint?

for(int i=1;i<11;i++){
//模拟多个请求
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra("requestID", i);
startService(intent);
}

for(int i=1;i<11;i++){
//模拟多个请求
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra("requestID", i);
startService(intent);
}

onHandleIntent的处理代码:

[java]
view plaincopyprint?

@Override
protected void onHandleIntent(Intent intent) {

int requestID = intent.getIntExtra("requestID", 0);
Log.d(TAG, "onHandleIntent,thread id:"+Thread.currentThread().getId());
Log.d(TAG, "onHandleIntent,requestID:"+requestID);

try {
Thread.sleep(2000);
} catch (Exception e) {
}
}

@Override
protected void onHandleIntent(Intent intent) {

int requestID = intent.getIntExtra("requestID", 0);
Log.d(TAG, "onHandleIntent,thread id:"+Thread.currentThread().getId());
Log.d(TAG, "onHandleIntent,requestID:"+requestID);

try {
Thread.sleep(2000);
} catch (Exception e) {
}
}

执行结果:



可以看出:
1.所有的请求都是在同一个worker thread中进行;
2.完全按照请求顺序的;
3.只有全部执行完才ondestory
还有一点非常重要:如果要override其他方法(onCreate,onStartCommand,onStart,onDestory),一定要调用父类的实现。因为父类的实现才是能够使用intentservice的关键(oncreate方法初始化一个workder thread,onstart方法将intent包装为message发送到消息队列)。不像service中几乎所有的方法都是空实现。

3.5 AIDL
AIDL(android interface definition language),适用于进程间通信。由于在android系统中不同进程之间不能直接通信,所以使用了AIDL进行规范通信。注意AIDL适用于IPC且service中处理多线程,如果是进程内部通信直接使用bindService;如果需要IPC但是不需要处理多线程可以使用Messenger。能尽量不使用就不适用。
再来看具体操作:
server端
1.创建aidl文件

[java]
view plaincopyprint?

package com.example.aidl;
import com.example.aidl.Person;
interface IMyAIDL{
int add(int a ,int b);
com.example.aidl.Person getPerson();
}

package com.example.aidl;
import com.example.aidl.Person;
interface IMyAIDL{
int add(int a ,int b);
com.example.aidl.Person getPerson();
}
在aidl文件中既支持一些有限的数据类型:String、原生数据类型、List、Map等。如果需要使用自定义的类,首先要创建一个该类的aidl文件:Person.aidl

[java]
view plaincopyprint?

package com.example.aidl; parcelable Person;

package com.example.aidl;
parcelable Person;

然后让Person实现Parcelable接口:

[java]
view plaincopyprint?

package com.example.aidl; import android.os.Parcel; import android.os.Parcelable; public class Person implements Parcelable { private String bookName; private double price; public Person() {} public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Person(Parcel in) { bookName = in.readString(); price = in.readDouble(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(bookName); dest.writeDouble(price); } public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() { @Override public Person[] newArray(int size) { // TODO Auto-generated method stub return null; } @Override public Person createFromParcel(Parcel source) { // TODO Auto-generated method stub return new Person(source); } }; @Override public int describeContents() { // TODO Auto-generated method stub return 0; } }

package com.example.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
private String bookName;
private double price;
public Person() {}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Person(Parcel in) {
bookName = in.readString();
price = in.readDouble();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
dest.writeDouble(price);
}
public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person[] newArray(int size) {
// TODO Auto-generated method stub
return null;
}
@Override
public Person createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new Person(source);
}
};
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
}
关于Parcelable接口的作用和如何实现不是这里介绍的重点,有兴趣的可以查看资料

2.service中实现该接口

[java]
view plaincopyprint?

IMyAIDL.Stub stub = new Stub() {
/**
* 模拟提供的服务操作
* */
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public Person getPerson() throws RemoteException {
Person person = new Person();
person.setBookName("平凡的世界");
person.setPrice(100.9);
return person;
}
};

IMyAIDL.Stub stub = new Stub() {
/**
* 模拟提供的服务操作
* */
@Override
public int add(int a, int b) throws RemoteException {
return a+b;
}
@Override
public Person getPerson() throws RemoteException {
Person person = new Person();
person.setBookName("平凡的世界");
person.setPrice(100.9);
return person;
}
};

并在onBind方法中返回该实例:

[java]
view plaincopyprint?

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.d(TAG, "MyService onBind," + this);
return stub;
}

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.d(TAG, "MyService onBind," + this);
return stub;
}


3.配置service中的intent-filter,因为client中调用时使用的是隐式Intent:

[java]
view plaincopyprint?

<service android:name="com.example.servicedemo.MyService" > <intent-filter> <action android:name="com.example.servicedemo.MyService.IMyAIDL" /> </intent-filter> </service>

<service android:name="com.example.servicedemo.MyService" >
<intent-filter>
<action android:name="com.example.servicedemo.MyService.IMyAIDL" />
</intent-filter>
</service>


刚才说的是server端的操作,接下来介绍一下client端操作:
1.将server中包括包在类的aidl拷到client
2.bindService中使用隐式Intent,其他操作和本地绑定一样。
3.在serviceConnection中的onServiceConnected方法将Ibinder对象转换成AIDL对象xxx.Stub.asInterface()。这样就可以调用AIDL中定义的方法了。

[java]
view plaincopyprint?

private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "connection onServiceDisconnected");
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "connection onServiceConnected,IBinder:" + service);
IMyAIDL myAIDL = IMyAIDL.Stub.asInterface(service);//将IBinder对象转换成IMyAIDL对象,然后调用该对象定义的方法
try {
Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.add(10, 11));
Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.getPerson().getBookName());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
};

private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "connection onServiceDisconnected");
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "connection onServiceConnected,IBinder:" + service);
IMyAIDL myAIDL =  IMyAIDL.Stub.asInterface(service);//将IBinder对象转换成IMyAIDL对象,然后调用该对象定义的方法
try {
Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.add(10, 11));
Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.getPerson().getBookName());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
};

绑定service:

[java]
view plaincopyprint?

Intent intent = new Intent("com.example.servicedemo.MyService.IMyAIDL"); bindService(intent, connection, BIND_AUTO_CREATE);

Intent intent = new Intent("com.example.servicedemo.MyService.IMyAIDL");
bindService(intent, connection, BIND_AUTO_CREATE);


3.6 Parcelable接口
parcelable接口的作用和java中serializable接口一样,都是为了序列化。序列化的主要目的是为了保存和传递对象类型数据(网络中、IPC中),
使用方法:实现Parcelable接口、重写writeToParcel(对象->parcel)、CREATOR变量(主要是其createFromParcel方法,Parcel->对象)。
java中还使用了Serializable接口。两者的使用场景不一样:
Serializable:对象保存到本地,数据库等。主要是持久化数据,磁盘操作。
Parcelable:是android专门为不同组件之间或者IPC时定义的一种方式,主要是内存中,显然要高效快一些。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: