Service

http://blog.csdn.net/yujun411522/article/details/46008947
本文出自:【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对象。   
  1. public IBinder onBind(){  
  2.           //  
  3.           return binder;  
  4.      }  
  5.      class MyBinder extends Binder{  
  6.           //提供的操作  
  7.      }  
public IBinder onBind(){
          //
          return binder;
     }
     class MyBinder extends Binder{
          //提供的操作
     }
2.clinet调用bindService(Intent,ServiceConnection,int)。主要是提供一个serviceconnection类。
  1. ServiceConnection connection = new ServiceConnection(Component){  
  2.           //与service连接失败  
  3.           public void onServiceDisconnected(){  
  4.                //当connection异常结束,如果service崩溃、被杀死时。注意,此方法不会在unbind时执行。  
  5.           }  
  6.            //与service连接成功  
  7.           public void onServiceConnected(ComponentName,IBinder){  
  8.                     //当成功返回service中onBind方法中的IBinder对象时调用  
  9.                    MyBinder binder= (MyBinder)service;  
  10.                     //得到service的binder,然后进行操作  
  11.           }  
  12.      }  
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
  1. @Override  
  2.    public void onCreate() {  
  3.        // TODO: It would be nice to have an option to hold a partial wakelock  
  4.        // during processing, and to have a static startService(Context, Intent)  
  5.        // method that would launch the service & hand off a wakelock.  
  6.   
  7.   
  8.        super.onCreate();  
  9.        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");//工作线程名称  
  10.        thread.start();  
  11.   
  12.   
  13.        mServiceLooper = thread.getLooper();  
  14.        mServiceHandler = new ServiceHandler(mServiceLooper);  
  15.    }  
 @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方法。
  1. @Override  
  2.    public void onStart(Intent intent, int startId) {  
  3.        Message msg = mServiceHandler.obtainMessage();  
  4.        msg.arg1 = startId;  
  5.        msg.obj = intent;  
  6.        mServiceHandler.sendMessage(msg);//利用handler 和message进行通信  
  7.    }  
 @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的消息处理函数:
  1. private final class ServiceHandler extends Handler {  
  2.     public ServiceHandler(Looper looper) {  
  3.         super(looper);  
  4.     }  
  5.   
  6.   
  7.     @Override  
  8.     public void handleMessage(Message msg) {  
  9.         onHandleIntent((Intent)msg.obj);//调用onHandleIntent方法  
  10.         stopSelf(msg.arg1);  
  11.     }  
  12. }  
    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
构造方法:   
  1. public MyIntentService(){  
  2.          //为工作线程提供一个name  
  3.          super("worker thread name");  
  4.     }  
  5.  @Override  
  6.  protected void onHandleIntent(Intent intent) {  
  7.       Log. d( TAG, "onHandleIntent,thread id:"+Thread.currentThread ().getId());  
  8.       Log. d( TAG, "onHandleIntent,intent:" +intent.toString());  
  9.  }  
 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是在子线程中处理的。
下面模拟多个请求:
  1. for(int i=1;i<11;i++){  
  2. //模拟多个请求  
  3. Intent intent = new Intent(MainActivity.this, MyIntentService.class);  
  4. intent.putExtra("requestID", i);  
  5. startService(intent);  
  6. }  
for(int i=1;i<11;i++){
//模拟多个请求
Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra("requestID", i);
startService(intent);
}
onHandleIntent的处理代码:
  1. @Override  
  2.     protected void onHandleIntent(Intent intent) {  
  3.           
  4.         int requestID = intent.getIntExtra("requestID"0);  
  5.         Log.d(TAG, "onHandleIntent,thread id:"+Thread.currentThread().getId());  
  6.         Log.d(TAG, "onHandleIntent,requestID:"+requestID);  
  7.           
  8.         try {  
  9.             Thread.sleep(2000);  
  10.         } catch (Exception e) {  
  11.         }  
  12.     }  
@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文件
  1. package com.example.aidl;  
  2. import com.example.aidl.Person;  
  3. interface IMyAIDL{  
  4.   int add(int a ,int b);  
  5.   com.example.aidl.Person getPerson();  
  6. }      
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
  1. package com.example.aidl;  
  2. parcelable Person;  
package com.example.aidl;
parcelable Person;
然后让Person实现Parcelable接口:
  1. package com.example.aidl;  
  2. import android.os.Parcel;  
  3. import android.os.Parcelable;  
  4. public class Person implements Parcelable {  
  5.     private String bookName;  
  6.     private double price;  
  7.     public Person() {}  
  8.     public String getBookName() {  
  9.         return bookName;  
  10.     }  
  11.     public void setBookName(String bookName) {  
  12.         this.bookName = bookName;  
  13.     }  
  14.     public double getPrice() {  
  15.         return price;  
  16.     }  
  17.     public void setPrice(double price) {  
  18.         this.price = price;  
  19.     }  
  20.     public Person(Parcel in) {  
  21.         bookName = in.readString();  
  22.         price = in.readDouble();  
  23.     }  
  24.     @Override  
  25.     public void writeToParcel(Parcel dest, int flags) {  
  26.         dest.writeString(bookName);  
  27.         dest.writeDouble(price);  
  28.     }  
  29.     public static final Parcelable.Creator<Person> CREATOR = new Creator<Person>() {  
  30.         @Override  
  31.         public Person[] newArray(int size) {  
  32.             // TODO Auto-generated method stub  
  33.             return null;  
  34.         }  
  35.         @Override  
  36.         public Person createFromParcel(Parcel source) {  
  37.             // TODO Auto-generated method stub  
  38.             return new Person(source);  
  39.         }  
  40.     };  
  41.     @Override  
  42.     public int describeContents() {  
  43.         // TODO Auto-generated method stub  
  44.         return 0;  
  45.     }  
  46. }  
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中实现该接口
  1. IMyAIDL.Stub stub = new Stub() {  
  2.         /** 
  3.          * 模拟提供的服务操作 
  4.          * */  
  5.         @Override  
  6.         public int add(int a, int b) throws RemoteException {  
  7.             return a+b;  
  8.         }  
  9.         @Override  
  10.         public Person getPerson() throws RemoteException {  
  11.             Person person = new Person();  
  12.             person.setBookName("平凡的世界");  
  13.             person.setPrice(100.9);           
  14.             return person;  
  15.         }  
  16.     };    
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方法中返回该实例:
  1. @Override  
  2.     public IBinder onBind(Intent intent) {  
  3.         // TODO Auto-generated method stub  
  4.         Log.d(TAG, "MyService onBind," + this);  
  5.         return stub;  
  6.     }  
@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:
  1. <service android:name="com.example.servicedemo.MyService" >  
  2.             <intent-filter>  
  3.                 <action android:name="com.example.servicedemo.MyService.IMyAIDL" />  
  4.             </intent-filter>  
  5. </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中定义的方法了。
  1. private ServiceConnection connection = new ServiceConnection() {  
  2.         @Override  
  3.         public void onServiceDisconnected(ComponentName name) {  
  4.             Log.d(TAG, "connection onServiceDisconnected");  
  5.         }  
  6.   
  7.         @Override  
  8.         public void onServiceConnected(ComponentName name, IBinder service) {  
  9.             Log.d(TAG, "connection onServiceConnected,IBinder:" + service);  
  10.             IMyAIDL myAIDL =  IMyAIDL.Stub.asInterface(service);//将IBinder对象转换成IMyAIDL对象,然后调用该对象定义的方法  
  11.             try {  
  12.                 Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.add(1011));                
  13.                 Log.d(TAG, "myAIDL.add(10, 11)" + myAIDL.getPerson().getBookName());                  
  14.             } catch (RemoteException e) {  
  15.                 // TODO Auto-generated catch block  
  16.                 e.printStackTrace();  
  17.             }  
  18.               
  19.         }  
  20.     };  
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:

  1. Intent intent = new Intent("com.example.servicedemo.MyService.IMyAIDL");  
  2. 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时定义的一种方式,主要是内存中,显然要高效快一些。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值