Services 综合介绍

来源:互联网 发布:手机淘宝领取淘金币 编辑:程序博客网 时间:2024/06/16 01:08

Services 综合介绍

官方:http://developer.android.com/guide/components/services.html
简介:Service是android系统的组件之一,它可以用来长时间在后台执行任务,这里需要注意的是Service运行在主线程上,因此不适于用来执行耗时操作,如果存在耗时任务如网络连接、MP3播放,我们应该在Service中另起线程来执行这些任务。 这里需要区分的是长时间在后台运行和耗时这两个概念并不相同。 Service可以用来处理网络交互、音乐播放、文件操作、联系content provider等任务。 Service可以被其他组件启动并保持运行状态,即使用户可能已经切换到其他应用去操作。当然,Service也可以被绑定运行,这样它的生命周期就和绑定的客户端相关联,不仅同应用的组件可以与它绑定,其他应用也可以绑定(IPC InterProcess Communication远程通信)。
*Service的两种运行方式:*
独立运行:这种运行方式是指Service被其他组件(如Activity)通过调用startService方法启动。由这种方式启动的Service可以保持一直运行,而与启动它的组件的状态无关,即使启动它的组建已经被销毁。通常这种独立启动的Service只需要执行单一的任务,而不必与启动它的组件联系。比如,某个Service可能用来下载或者上传一个文件到网络,当这个任务完成以后,Service就应该销毁自己。(这里的特点就是保证了即使启动它的组件已经被销毁,也能保证任务得到完整执行)
绑定运行:Service除了独立启动去执行单一任务,它也可以被其他组件绑定,通过bindService方法启动运行。绑定启动的Service和绑定它的客户端将拥有一个接口,实现发起请求、获得结果等任务,Service不仅可以在某一应用内被绑定,它还能实现跨进程绑定,即其他的应用也可以绑定到这个服务。以绑定启动方式运行的Service的生命周期将与和它绑定的组件生命周期相关联,即“非同年同月同日生,但一定同年同月同日同时死”。 一个Service允许同时被多个组件绑定,当所有与它绑定的组件都被销毁时,这个Service也会被销毁。
这里需要注意的是,Service独立运行和绑定运行两种方式并不是互斥的,我们可以同时调用startService和bindService来使这个Service运行起来。
*创建一个Service:*
我们需要继承Service类或者继承它的一个子类来创建我们自己的类,以下几个方法我们可能需要去覆盖:
onStartCommand() 每次我们通过startService()去启动Service的时候,onStartCommand方法都会得到执行,即使之前已经调用过startService方法。如果这个onStartCommand得到过执行,那么这个Service就是以独立运行方式运行的,因此我们应该在它的任务完成时通过stopSelf()方法或者stopService方法去关闭这个Service,总之,系统是不会去关闭它的(除非内存吃紧)。 当然,如果我们不会通过startService来启动这个Service,我们也就可以不重写这个方法。
onBind() 当我们通过bindService方法来绑定到Service的时候,这个方法会得以执行,并返回一个IBinder对象,这个IBinder对象就是客户端与Service的桥梁,可以通过我们在里面定义的接口,实现我们的交互。 当然,如果我们不会绑定到这个Service,我们也可以不重写此方法,默认它会返回NULL。 这里需要注意的是,onBind方法并不是每次绑定都会运行,它只会在第一次绑定的时候才会执行。
onCreate() 当Service还没运行时,我们调用startService或者bindService启动Service,都会首先调用onCreate。但是如果Service已经在运行了,之后调用startService和bindService都不会再执行onCreate。
onDestory() 当Service将要被销毁时调用这个方法,在这个方法里,我们需要去释放Service所占用的各种资源,如线程、注册的监听等。

一般情况下,Service不会被系统杀死,但是当系统内存极度紧张时,Service将可能被杀死,在此之后,当系统内存不再那么紧张时,系统可能会重启这个Service(具体重启时机和onStartService返回的值有关),因此我们需要注意系统重启Service的应当如何处理。
在AndroidManifest中声明Service:
和acitivty一样,每一个Service都需要在manifest中声明,声明格式如下:

<manifest ... >  ...  <application ... >     <service android:enabled=["true" | "false"]         android:exported=["true" | "false"]         android:icon="drawable resource"         android:isolatedProcess=["true" | "false"]         android:label="string resource"         android:name="string"         android:permission="string"         android:process="string"> <intent-filter android:icon="drawable resource"               android:label="string resource"               android:priority="integer" >       </intent-filter><meta-data android:name="string"           android:resource="resource specification"           android:value="string" /> </service>      ...  </application></manifest>

可以看到,Service可以配置许多属性,但是只有android:name是必须的,他指定了Service的类名。
为了保证应用的安全性,你应该使用指定的Intent(类名限定)来启动或者绑定到Service,而不要去声明intent filters。如果允许一定的歧义性,让用户选择具体哪一个Service,也可以声明intent filters,但是你必须在intent中通过setPackage()方法来减少这个歧义。
另外,如果你不希望Service提供跨进程服务,可以设置android:exported为false。
创建一个独立方式运行的Service:
对于以独立方式运行的Service,如果我们需要在启动它的时候传入一些数据,可以在startService(Intent)中的intent对象中传入,它可以包含少量的数据或者一个可以获取到数据的链接。
通常情况下,我们可以通过继承以下两个类来创建一个以独立方式运行的Service。
直接继承Service类: Service类是一个抽象类。在继承这个类时,我们需要另外创建创建线程来处理我们的任务操作。
继承IntentService类: IntentService类是Service类的子类,它使用一个工作线程来统一处理所有的请求。当你不需要多个线程处理任务时,直接继承IntentService类是最好的选择。所有你需要做的就是重写onHandleIntent()方法,这个方法用来处理每个包含请求的Intent。
*下面具体介绍如何继承上面两个类:*
继承IntentService:
IntentService的特点重点内容
1、 创建一个工作线程,用于处理onStartCommand()传递的intents对象(onStartCommand多次被调用,就会传递多个过来);
2、 创建一个工作队列来将onStartCommand传递的intent按序组织起来,并依次提交给onHandleIntent,每次提交都是在上一个intent已经处理完成后;
3、 当将工作队列中所有intent处理完以后,它会自动关闭Service,而不用我们去关闭它;
4、 onBind()的默认实现会是返回null;
综合IntentService的所有特点,继承Service时,我们的唯一工作就是重写onHandleIntent()方法。

public class HelloIntentService extends IntentService {  /**A constructor is required, and must call the super IntentService(String) constructor with a name for the worker thread.   */  public HelloIntentService() {      super("HelloIntentService");  }  /**   * The IntentService calls this method from the default worker thread withthe intent that started the service. When this method returns, IntentService stops the service, as appropriate.   */  @Override  protected void onHandleIntent(Intent intent) {      // Normally we would do some work here, like download a file.      // For our sample, we just sleep for 5 seconds.      long endTime = System.currentTimeMillis() + 5*1000;      while (System.currentTimeMillis() < endTime) {          synchronized (this) {              try {                  wait(endTime - System.currentTimeMillis());              } catch (Exception e) {       }}}}}

继承Service:
当我们需要通过多线程来完成我们提交的任务时,我们可以通过继承Service类来实现,我们只需要在onStartCommand中每次调用都启动一个线程来处理任务就可以了。但是官方文档,仅仅提供了一个单线程处理任务的示例,它实现的功能和上面继承IntentService是一样的,但是这里需要更多的代码:

public class HelloService extends Service {  private Looper mServiceLooper;  private ServiceHandler mServiceHandler;  // Handler that receives messages from the thread  private final class ServiceHandler extends Handler {      public ServiceHandler(Looper looper) {          super(looper);}      @Override      public void handleMessage(Message msg) {        // Normally we would do some work here, like download a file.       // For our sample, we just sleep for 5 seconds.          long endTime = System.currentTimeMillis() + 5*1000;          while (System.currentTimeMillis() < endTime) {              synchronized (this) {                  try {                      wait(endTime - System.currentTimeMillis());                  } catch (Exception e) {                  }}}          // Stop the service using the startId, so that we don't stop          // the service in the middle of handling another job          stopSelf(msg.arg1);  } }  @Override  public void onCreate() {   // Start up the thread running the service.  Note that we create a  // separate thread because the service normally runs in the              //process'smain thread, which we don't want to block. We also make it //background priority so CPU-intensive work will not disrupt our UI.    HandlerThread thread = new HandlerThread("ServiceStartArguments",            Process.THREAD_PRIORITY_BACKGROUND);    thread.start();    // Get the HandlerThread's Looper and use it for our Handler    mServiceLooper = thread.getLooper();    mServiceHandler = new ServiceHandler(mServiceLooper);  }  @Override  public int onStartCommand(Intent intent, int flags, int startId) {      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();      // For each start request, send a message to start a job and deliver the      // start ID so we know which request we're stopping when we finish the job      Message msg = mServiceHandler.obtainMessage();      msg.arg1 = startId;      mServiceHandler.sendMessage(msg);      // If we get killed, after returning from here, restart      return START_STICKY;  }  @Override  public IBinder onBind(Intent intent) {      // We don't provide binding, so return null      return null;  }  @Override  public void onDestroy() {    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();  }}

以独立方式运行的Service如何返回一个结果给客户端呢?官方文档介绍了一个方法,在startService(Intent)传递的Intent中加入一个PendingIntent对象,使Service在完成以后可以通过它发布一个广播来返回结果。
创建一个绑定方式运行的Service:
当你需要实现与Service实现交互,或者你希望把本应用的某些功能发布给其他应用时,你应该创建一个以绑定方式运行的Service。
创建绑定运行的Service,我们必须重写IBinder onBind (Intent intent)方法,返回的Ibinder对象定义了客户端与Service交互的接口。我们通过bindService()去绑定一个Service,通过unBindService解绑,我们不必去关心这个Service合适关闭,因为当所有与它绑定的客户端解绑以后,它会自动关闭。
我们有多种方式去实现Service与绑定它的客户端实现交互,实现绑定方式运行的Service比独立方式运行的Service要复杂许多,官方文档另外有一篇文章专门介绍,我们这里也将在后续文章中专门介绍。
发送通知给用户:
在Service执行的各个阶段,我们可以发送Toast通知或者状态栏通知,其中状态栏通知,我们可以引导用户执行一些操作,比如启动一个Activity。
运行前台Service:
一个前台Service表示这个Service执行的任务会受到用户的关注,因此它应该极不容易被系统杀死。一个前台Service必须提供一个状态栏通知,直到它退出前台或者已经关闭。
比如一个播放音乐的Service应该作为前台Service运行,因为用户需要意识到他自己的操作,看到当前播放的状态,或者依靠它启动一个Activity。
Service调用startForeground方法即可启动前台运行,这个方法有两个参数:1、一个integer类型的notification Id(非0)和一个Notification。如下所示:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),        System.currentTimeMillis());Intent notificationIntent = new Intent(this, ExampleActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);notification.setLatestEventInfo(this, getText(R.string.notification_title),        getText(R.string.notification_message), pendingIntent);startForeground(ONGOING_NOTIFICATION_ID, notification);

要移除Service的前台运行,调用stopForeground (boolean removeNotification)即可,当removeNotification为true时则移除通知,为false则保留通知,它只会停止前台运行,但并不会停止Service。 当Service停止时,它会自动移除通知。

0 0
原创粉丝点击