Android service学习

来源:互联网 发布:网络直播招聘骗局 编辑:程序博客网 时间:2024/06/03 20:59

根据疯狂Android讲义一书学习:

Service介绍

Service作为安卓四大组建之一,也需要在AndroidManifest.xml中配置,并且根据<intent-filter.../>属性指定可以被哪些Intent启动。

Service和Activity来自相同基类Context,也可一调用getResoureces(),getContentResolver()等方法。


Service的生命周期:

  • IBinder onBind(Intent intent): 该方法是Service子类必须实现的方法,返回一个IBinder对象,应用程序通过该IBinder对象与Service组建通信。
  • void onCreate():第一次创立时回调。
  • void onDestroy():被关闭之前回调。
  • void onStartCommand(Intent intent, int flags, int startId):早期版本为void onStart(Intent intent, int startId),每次客户端调用startService(Intent)方法启动Service时回调。
  • boolean onUnbind(Intent intent):当该Service上绑定的客户端都断开链接时回调。

下边定义了一个Service组件

/** * */package org.crazyit.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;public class FirstService extends Service{// 必须实现的方法@Overridepublic IBinder onBind(Intent arg0){return null;}// Service被创建时回调该方法。@Overridepublic void onCreate(){super.onCreate();System.out.println("Service is Created");}// Service被启动时回调该方法@Overridepublic int onStartCommand(Intent intent, int flags, int startId){System.out.println("Service is Started");return START_STICKY;}// Service被关闭之前回调。@Overridepublic void onDestroy(){super.onDestroy();System.out.println("Service is Destroyed");}}
上边代码是基础的Service组建必须实现的方法。


然后需要在AndroidManifest.xml中配置:

<!-- 配置一个Service组件 --><service android:name=".FirstService"><intent-filter><!-- 为该Service组件的intent-filter配置action --><action android:name="org.crazyit.service.FIRST_SERVICE" /></intent-filter></service>

和Activity类似,指定intent-filter标签说明该Service可以被哪些Intent启动。

和Activity不同的是,不需要android:label等属性,因为Service永远在后台运行,没必要指定标签。


介绍完基础的Service类和配置后说一下Service的两种启动方式

  • 通过Context的startService()方法启动:如果用这种方式启动,访问者和Service之间没有关联,如果访问者退出,Service依然运行。
  • 通过Context的bindService()方法启动:如果用这种方式启动,访问者和Service绑定在了一起,如果访问者退出,Service也就终止。


启动和停止Service

下边的Activity作为Service的访问者,由两个按钮组成,一个用来启动Service,另一个用来关闭Service。

package org.crazyit.service;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class StartServiceTest extends Activity{Button start, stop;@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);// 获取程序界面中的start、stop两个按钮start = (Button) findViewById(R.id.start);stop = (Button) findViewById(R.id.stop);// 创建启动Service的Intentfinal Intent intent = new Intent();// 为Intent设置Action属性intent.setAction("org.crazyit.service.FIRST_SERVICE");start.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0){// 启动指定Serivce<strong>startService(intent);</strong>}});stop.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0){// 停止指定Serivce<strong>stopService(intent);</strong>}});}}

可以看到启动Service的方法为startService(Intent intent),关闭Service的方法为stopService(Intent intent)。

如果连续点击三次启动按钮,可以发现onStartCommand()方法被调用了3次,而onStart()方法只有第一次被回调。


绑定本地Service并与之通信

使用startService()、stopService()的方式启动、停止 Service,访问者和Service之间没有关联,也无法进行通信和数据交换。

如果需要进行方法调用或数据交换,应该使用bindService()和unbindService()方式。

先介绍Context的bindService(Intent service,ServiceConnection conn,int flags)方法的三个参数:

  • Intent service:该参数通过Intent指定要启动哪个Service。
  • ServiceConnection conn:该参数是一个ServiceConnection对象,该对象用于监听访问者和Service之间的连接情况。当访问者与Service连接成功时回调ServiceConnection对象的onServiceConnected(ComponentName name, IBinder binder)方法;当连接断开时回调onServiceDisconnected(ComponentName name)方法。
  • Int flags:该参数指定绑定时是否自动创建Service。如果为0则不自动创建,或者为BIND_AUTO_CREATE。

通信是通过onServiceConnected方法的IBinder对象进行的,Service类必须实现onBind(IBinder binder)方法,该方法的参数binder会传给ServiceConnect的onServiceConnected方法,这样访问者就可以通过IBinder对象与Service进行通信。

下边的例子实现了onBind()方法,并且实现了自己的IBinder的实现类:

package org.crazyit.service;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;public class BindService extends Service{private int count;private boolean quit;// 定义onBinder方法所返回的对象private MyBinder binder = new MyBinder();// 通过继承Binder来实现IBinder类public class MyBinder extends Binder //①{public int getCount(){// 获取Service的运行状态:countreturn count;}}// 必须实现的方法,绑定该Service时回调该方法@Overridepublic IBinder onBind(Intent intent){System.out.println("Service is Binded");// 返回IBinder对象return binder;}// Service被创建时回调该方法。@Overridepublic void onCreate(){super.onCreate();System.out.println("Service is Created");// 启动一条线程、动态地修改count状态值new Thread(){@Overridepublic void run(){while (!quit){try{Thread.sleep(1000);}catch (InterruptedException e){}count++;}}}.start();}// Service被断开连接时回调该方法@Overridepublic boolean onUnbind(Intent intent){System.out.println("Service is Unbinded");return true;}// Service被关闭之前回调该方法。@Overridepublic void onDestroy(){super.onDestroy();this.quit = true;System.out.println("Service is Destroyed");}}

上边代码中的①部分是一个继承了Binder(实现了IBinder接口)的内部类。

下边的Activity会绑定上边的Service,并且通过MyBinder获取Service的内部数据(Count)。该Activity包含三个按钮,第一个用于绑定Service,第二个用于解除绑定,第三个用于获取Service的

package org.crazyit.service;import android.app.Activity;import android.app.Service;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class BindServiceTest extends Activity{Button bind, unbind, getServiceStatus;// 保持所启动的Service的IBinder对象BindService.MyBinder binder;// 定义一个ServiceConnection对象private ServiceConnection conn = new ServiceConnection(){// 当该Activity与Service连接成功时回调该方法@Overridepublic void onServiceConnected(ComponentName name, IBinder service){System.out.println("--Service Connected--");// 获取Service的onBind方法所返回的MyBinder对象binder = (BindService.MyBinder) service; //①}// 当该Activity与Service断开连接时回调该方法@Overridepublic void onServiceDisconnected(ComponentName name){System.out.println("--Service Disconnected--");}};@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);// 获取程序界面中的start、stop、getServiceStatus按钮bind = (Button) findViewById(R.id.bind);unbind = (Button) findViewById(R.id.unbind);getServiceStatus = (Button) findViewById(R.id.getServiceStatus);// 创建启动Service的Intentfinal Intent intent = new Intent();// 为Intent设置Action属性intent.setAction("org.crazyit.service.BIND_SERVICE");bind.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View source){// 绑定指定SerivcebindService(intent, conn, Service.BIND_AUTO_CREATE);}});unbind.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View source){// 解除绑定SerivceunbindService(conn);}});getServiceStatus.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View source){// 获取、并显示Service的count值Toast.makeText(BindServiceTest.this,"Serivce的count值为:" + binder.getCount(),Toast.LENGTH_SHORT).show(); //②}});}}
上边代码中的①部分把onBind(Intent intent)方法返回的Binder对象给到ServiceConnection对象里。

代码②通过Binder的getCount()方法访问Service的数据。

当activity调用unbindService()时会调用Service的onUnbind()方法和onDestroy()方法。

与之前通过startService访问Service不同,之前每次点击启动服务按钮都会回调Service的onStartCommand()方法,但如果多次按下绑定按钮,只调用一次onBind()方法。


Service的生命周期

上边讲的两种情况,Service的生命周期也有所不同。

第一种通过startService()启动的生命周期为:onCreate()-->onStartCommand()-->onDestroy();

第二种通过bindService()启动的生命周期为:onCreate()-->onBind()-->onUnbind()-->onDestroy()。

还有一种情况是通过startService()启动,然后再通过bindService()去绑定:

onCreate()-->onStartCommand()-->onBind()-->onUnbind()-->onRebind()。

可以看到这时Context的unBindService()方法并不会回调Service的onDestory()方法。这是因为该service是通过startService启动起来的,这种方式建立的Service并没有和访问者真正的绑定,因此生命周期不会受到影响。解除绑定后Service依然存在,需要通过stopService()方法关闭。


使用IntentService

IntentService是Service的一个子类。

Service和它所在的应用位于同一个线程,因此不应该用来处理耗时任务。如果需要执行耗时任务,需要自己新起一个子线程,就像上边的例子,在onCreate方法中新起得子线程。

IntentService可以直接解决这个问题,对于异步的startService()请求,IntentService会建立一个队列并在新建的worker线程里依次处理Intent。

归纳IntentService的特征:

  • IntentService会新建单独的worker thread来处理所有的intent请求。
  • IntentService的onHandleIntent()方法已经在新的线程里运行,开发者无需维护多线程。
  • 当IntentService处理完所有的Intent后会自动停止,无需开发者再调用Service的stopSelf()方法(相当于访问Context的stopService()方法)来停止该Service。
  • 默认实现了onBind()方法,返回null。
  • 默认实现了onStartCommand()方法,将Intent放入队列中。

因此实现IntentService无须必须重写onBind和onStartCommand方法,而需要重写onHandleIntent()方法。

下边的activity的两个按钮分别启动一个普通service一个intentService来进行耗时任务:

package org.crazyit.service;import android.os.Bundle;import android.view.View;import android.app.Activity;import android.content.Intent;public class IntentServiceTest extends Activity{@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}public void startService(View source){// 创建需要启动的Service的IntentIntent intent = new Intent(this, MyService.class);// 启动ServicestartService(intent);}public void startIntentService(View source){// 创建需要启动的IntentService的IntentIntent intent = new Intent(this, MyIntentService.class);// 启动IntentServicestartService(intent);}}
MyService继承Service,MyIntentService继承IntentService,下边是两个Service的实现:

MyService:

package org.crazyit.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;public class MyService extends Service{@Overridepublic IBinder onBind(Intent intent){return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId){// 该方法内执行耗时任务可能导致ANR(Application Not Responding)异常long endTime = System.currentTimeMillis() + 20 * 1000;System.out.println("onStart");while (System.currentTimeMillis() < endTime){synchronized (this){try{wait(endTime - System.currentTimeMillis());}catch (Exception e){}}}System.out.println("---耗时任务执行完成---");return START_STICKY;}}
上边的 service在onStartCommand方法里执行了一个耗时20秒的任务,因为阻塞主线程所以会造成ANR(Application not responding)异常。
然后是IntentService:

package org.crazyit.service;import android.app.IntentService;import android.content.Intent;public class MyIntentService extends IntentService{public MyIntentService(){super("MyIntentService");}// IntentService会使用单独的线程来执行该方法的代码@Overrideprotected void onHandleIntent(Intent intent){// 该方法内可以执行任何耗时任务,比如下载文件等,此处只是让线程暂停20秒long endTime = System.currentTimeMillis() + 20 * 1000;System.out.println("onStart");while (System.currentTimeMillis() < endTime){synchronized (this){try{wait(endTime - System.currentTimeMillis());}catch (Exception e){}}}System.out.println("---耗时任务执行完成---");}}
可以看到在IntentService里并不需要再重写onBind和onStartCommand方法。而onHandleIntent里的任务会自动在新的worker thread里执行,从而不会阻塞主线程,因此不会造成ANR异常。


0 0