您的位置:首页 > 移动开发 > Android开发

Android开发四大组件之Service总结

2016-08-03 09:26 633 查看
转载请注明出处:http://blog.csdn.net/li0978/article/details/52100414

Service是安卓开发四大组件中和Activity最相似的组件,与Activity不同的是,Service是没有界面的,一直在后台运行。四大组件都有自己的生命周期,service也不例外,并且service的生命周期最长。

Service生命周期中主要包含以下几个方法:

public class MyService extends Service {
/**
* 该方法是Service子类必须实现的方法,该方法可返回一个IBinder对象,可用于其他组件与service组件相互通信
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

/**
* service重新绑定时并且在onUnbind方法返回true的情况下能够执行回调此方法
* @param intent
*/
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}

/**
* service第一次创建后立即创建回调的方法
*/
@Override
public void onCreate() {
super.onCreate();
}

/**
* 其他组件每次调用startService(intent),此方法便会执行一次,用于其他组件向service传值,返回值的设置又能控制自身的重启情况。早期版本是onStart(),现已经过时
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

/**
* Service关闭之前将会调用该方法
*/
@Override
public void onDestroy() {
super.onDestroy();
}

/**
* service解除绑定断开连接时调用该方法。
* @param intent
* @return
*/
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}

在Android系统中针对service操作有两种方式:

1.通过Context的startService()和stopService(),这种方式访问者与service之间没有关联,因此Service和访问者之间无法进行通讯和访问数据,另外即使访问者退出了,service也仍然运行。

2.通过Context的bindService()和unbindService(),这种方式访问者与service绑定在一起,能够进行之间的通讯和数据访问,访问者一旦退出,service也终止了。



通过Context的startService()和stopService()

首先在AndroidManifast注册此服务,这里和Activity注册很相似,也可以设置过滤器,其中android:priority="1000"表示该服务的优先级设成最大。因为service没有界面所以我们就没必要设置lable,icon等标签了。



<service android:name=".MyService">
<intent-filter android:priority="1000">
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
开启服务:
Intent intent = new Intent(MainActivity.this,MyService.class);
startService(intent);
生命周期走向:onCreat --> onStartCommand
再次点击开启按钮生命周期走向:onStartCommand

停止服务:

Intent intent = new Intent(MainActivity.this,MyService.class);
stopService(intent);
生命周期走向:onDestroy
再次点击停止按钮生命周期走向:无

通过Context的bindService()和unbindService()

绑定服务调用bindService(Intent intent,ServiceConnection conn,int flags)。第一个参数:要启动的service。第二个参数:该参数是一个ServiceConnection对象,用于监听访问者和service的链接情况。第三个参数:指定绑定时是否自动创建service,一般指定Service.BIND_AUTO_CREATE(service自动创建启动),不想自动创建可设为0(service此时并没有启动,但是当service启动时也同时绑定了)。

既然访问者要与service进行通信,总要有一个中间桥梁来来沟通访问者和service。这个中间桥梁就是service中onBind()方法返回的IBinder对象(默认是返回null)。

private boolean isBind; //判断是否绑定
private MyBinder myBinder = new MyBinder();
public class MyBinder extends Binder{
public boolean isBind(){
return isBind;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.e("TAG","+++++++++++++++++++++++++++++onBind");
isBind = true;
return myBinder;
}

访问者类中建立ServiceConnection对象,内部有两个方法:onServiceConnected()回调表示成功绑定,此时我们可以拿到service中的IBinder对象,进而也就能取到service中我们想要的数据。onServiceDisconnected回调表示断开绑定,注意这里的断开是由于异常终止或其他原因终止,也就是说访问者主动断开是不会回调的(一般情况下都不会回调此方法)。

private MyService.MyBinder iBinder;
//建立访问者与service的连接
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("TAG", "+++++++++++++++++++++++++onServiceConnected");
iBinder = (MyService.MyBinder) service;
}

@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("TAG", "+++++++++++++++++++++++++onServiceDisconnected");
}
};

以下两个生命周期指示仅仅是绑定和取消绑定并且绑定时自动创建服务的情况。

绑定服务:

Intent intent = new Intent(MainActivity.this, MyService.class);
bindService(intent, conn, Service.BIND_AUTO_CREATE);


生命周期走向:onCreat --> onBind -->>onServiceConnected

多次绑定无效只能绑定一次。

取消绑定:

if (iBinder!=null && iBinder.isBind()){
unbindService(conn);
}
生命周期走向:onUnbind --> onDestroy 
多次取消一定要注意取消过绑定了就不能再次取消绑定了,否则报异常错误。另外需注意如果访问者退出了也一定要取消绑定,例如在Activity中的onDestroy中取消绑定,否则会出现内存泄漏。

组合操作
a.绑定服务时自动创建启动服务(即第三个参数设置成Service.BIND_AUTO_CREATE)

1.操作:启动服务-->绑定服务-->解除绑定-->停止服务

生命周期走向:onCreat-->onStartCommand-->onBind-->>onServiceConnected-->onUnbind-->onDestroy

2.操作:绑定服务-->停止服务

生命周期走向:onCreat-->onBind-->>onServiceConnected

3.操作:启动服务-->绑定服务-->停止服务

生命周期走向:onCreat-->onStartCommand-->onBind-->>onServiceConnected

4.操作:绑定服务-->启动服务-->解除绑定

生命周期走向:onCreat-->onBind-->>onServiceConnected-->onStartCommand-->onUnbind

综上四种操作得出一个结论:无论是启动(停止)服务还是绑定(取消绑定)都要成双成对才能形成一个完善的生命周期。

b.绑定服务时 不自动创建启动服务(即第三个参数设置成0)

5.操作:绑定服务

生命周期走向:无

6.操作:绑定服务-->启动服务

生命周期走向:onCreate-->onBind-->onStartCommand-->>onServiceConnected

综上两种操作得出一个结论:如果绑定服务时不自动创建启动服务而随后再启动服务,此时再启动的同时也绑定了服务。

c.生命周期中的onUnbind方法返回值的设置。

7.操作:启动服务-->绑定服务-->解除绑定-->绑定服务-->解除绑定-->停止服务

返回值默认时,生命周期走向:onCreate-->onStartCommand-->onBind-->>onServiceConnected-->onUnbind-->>onServiceConnected-->onDestroy

第二次绑定服务时没有调用onBind方法,仅仅调用onServiceConnected,说明也绑定成功了,只是看着有点模糊。第二次解除绑定的时候没有调用onUnbind,当时停止服务时调用onDestroy,说明也取消绑定成功了,不过看着更加模糊。

返回值为true时,生命周期走向:onCreate-->onStartCommand-->onBind-->>onServiceConnected-->onRebind-->onUnbind-->>onServiceConnected-->onUnbind-->onDestroy

第二次绑定服务时还是没有调用onBind方法,当时调用onRebind方法,并且取消绑定的时候也调用了onUnbind方法。

综上对于多次绑定、取消绑定操作。只有在第一次绑定的时候才会调用onBind方法,但是每次都会在访问者连接回调onServiceConnected方法。绑定时生命周期中的onUnbind返回默认,在多次绑定、取消绑定操作的取消绑定的时候是不会调用onUnbind方法的,只有绑定时生命周期中的onUnbind返回true才会调用onUnbind方法,同时绑定过程也会调用onRebind方法。



生命周期中的onStartComand返回值设置


onStartComand使用时,返回的是一个(int)整形。  

这个整形可以有四个返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。  

它们的含义分别是:  

1):START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。  

2):START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务  

3):START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。     
4):START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。  

通常情况我们会选择返回一个START_REDELIVER_INTENT,保证service的稳定和数据的完整。

onStartComand参数flags含义 :flags表示启动服务的方式。

Additional data about this start request. Currently either 0, START_FLAG_REDELIVERY, or START_FLAG_RETRY.  

START_FLAG_REDELIVERY:如果你实现onStartCommand()来安排异步工作或者在另一个线程中工作, 那么你可能需要使用START_FLAG_REDELIVERY来让系统重新发送一个intent。这样如果你的服务在处理它的时候被Kill掉, Intent不会丢失.  
START_FLAG_RETRY:表示服务之前被设为START_STICKY,则会被传入这个标记。

IntentService使用

IntentService作为service的子类,继承IntentService,却不是一个普通service,它也有service的生命周期,却比一般的service多了一些特殊的功能。我们知道service和Activity很类似,它也有一个主线程,它的主线程同样也不能进行耗时操作,否则会报ANR错误。平时我们用service下载东西或者超时操作都是新建一个子线程。IntentService解决了这个不足,新建IntentService必须要有一个无参的构造方法和onHandleIntent()方法。无参的构造方法要传入一个字符串来命名工作线程(官方指出为了调试用),onHandleIntent()就是来处理耗时操作的。IntentService具有如下特征:

1.IntentService会创建单独的worker线程来处理Intent请求。IntentService会使用队列来管理所有请求的Intent,每当访问者通过Intent请求启动IntentService,Intentservice会将该Intent加入队列中。然后开启一条新的work线程来处理该Intent。保证同一时刻只处理一个intent请求。

2.IntentService会创建单独的worker线程来处理onHandlerIntent()方法实现的代码,开发者无需处理多线程问题。

3.当所有请求处理完成后。IntentService就会停止,开发者无需调用stopService()或者stopSelf()来停止IntentService。

public class MyIntentService extends IntentService {
@Override
public void onCreate() {
super.onCreate();
Log.e("TAG","++++++++++++++IntentService+++++++++++++++onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("TAG","++++++++++++++IntentService+++++++++++++++onStartCommand");
return super.onStartCommand(intent, flags, startId);
}

/**
*至少要有一个无参构造器,里面的字符串随便命名,只是为了命名工作线程,并且也只是为了调试。
*/
public MyIntentService() {
super("MyIntentService");
}

@Override
protected void onHandleIntent(Intent intent) {
Log.e("TAG","++++++++++++++IntentService+++++++++++++++onHandleIntent");
}

@Override
public void onDestroy() {
super.onDestroy();
Log.e("TAG","++++++++++++++IntentService+++++++++++++++onDestroy");
}
}
启动IntentService和启动一般的service一样:

Intent intent = new Intent(MainActivity.this, MyIntentService.class);
startService(intent);
启动一次生命周期走向:onCreat-->onStartCommand-->onHandleIntent-->onDestroy

如果耗时操作还未完成(此时IntentService还未关闭),多次启动IntentService生命周期走向:onCreat-->onStartCommand-->onHandleIntent-->onStartCommand-->onDestroy

综上多次启动IntentService每次都调用onStartCommand,但是onHandleIntent只调用一次。通常我们用IntentService做一些耗时的操作,比如下载,可以用Messenger来进行访问者和IntentService之间的通信。

访问者创建一个Handler来获取IntentService中动作信息。访问:

//接收IntentService中传来的消息
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what){
case MyIntentService.HANDLERINTENT_START:
Toast.makeText(MainActivity.this,"IntentService调用onHandleIntent()方法开始进行计算",Toast.LENGTH_LONG).show();
break;
case MyIntentService.HANDLERINTENT_OPERA:
intentservice_result_tv.setText(msg.arg1+"");
break;
case MyIntentService.HANDLERINTENT_FINISH:
Toast.makeText(MainActivity.this,"IntentService调用onHandleIntent()方法计算过程结束",Toast.LENGTH_LONG).show();
break;
}
}
};
访问者向IntentService传递Messenger对象:

Intent intent = new Intent(MainActivity.this, MyIntentService.class);
intent.putExtra(MyIntentService.EXTRA_MESSAGER, new Messenger(handler));
startService(intent);
IntentService中接受到访问者的Messenger对象并进行通信:

@Override
protected void onHandleIntent(Intent intent) {
Log.e("TAG","++++++++++++++IntentService+++++++++++++++onHandleIntent");
Bundle extras = intent.getExtras();
Messenger messenger = null;
if(extras != null){
messenger = (Messenger)extras.get(EXTRA_MESSAGER);
}
//通知计算开始
if (messenger!=null){
sendMessage(messenger,HANDLERINTENT_START,-1);
}
//通知计算进行中
for (int i=Integer.MIN_VALUE;i<Integer.MAX_VALUE;i++){
if (i%100000000==0){
if (messenger!=null){
sendMessage(messenger,HANDLERINTENT_OPERA,i);
}
}
}
//通知计算结束
if (messenger!=null){
sendMessage(messenger,HANDLERINTENT_FINISH,-1);
}
}

public void sendMessage(Messenger mesenger,int what,int result){
Message msg = Message.obtain( );
msg.what = what;
msg.arg1 = result;
try {
mesenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}


以上就是我对Android四大组件之一Service进行了一个完整总结,这些都是基础部分,基础把握好是一个关键。

service生命周期测试,启动,停止,绑定,取消绑定,以及IntentService与访问者通信Demo:

http://download.csdn.net/detail/li0978/9595036



 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: