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{ //提供的操作 }
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,然后进行操作 } }
执行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);
}
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进行通信
}
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);
}
}
显然是调用了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());
}
执行完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);
}
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) {
}
}
执行结果:
可以看出:
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();
}
[java]
view plaincopyprint?
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; } }
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;
}
};
并在onBind方法中返回该实例:
[java]
view plaincopyprint?
@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>
刚才说的是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();
}
}
};
绑定service:
[java]
view plaincopyprint?
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时定义的一种方式,主要是内存中,显然要高效快一些。
本文出自:【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时定义的一种方式,主要是内存中,显然要高效快一些。
相关文章推荐
- 多线程异步加载图片async_pictures
- 五、MongoDB的索引
- NOIP2010-普及组复赛模拟试题-第二题-数字积木
- 编写高质量代码改善C#程序的157个建议——建议45:为泛型类型参数指定逆变
- POJ 2251 Dungeon Master
- Android Layout Resource分析
- 二叉搜索树(Binary Search Tree)的查找
- Partition List
- 杭州电子科技大学acm---2007
- Handler
- HDU 1005.Number Sequence【很多问题是不能直接求的】【8月15】
- POJ 2013 Symmetric Order
- 程序是怎么运行的-总结于《程序是怎么跑起来的》
- linux command intro2 vi
- POJ 1321 棋盘问题
- 黑马程序员-Java高级:反射
- 转置位矩阵
- 黑马程序员----IO流(其他)
- Ridge Regression岭回归
- ExtJs4获取后台session springmvc