• Android Service:Creating a Started Service


     

    Creating a Started Service

      一个被开始的service(started service)是另一个组件调用startService()开启的,结果是这个service的onStartCommand()方法被调用。

      当一个service被start,它就拥有一个独立于开始它的组件的生命周期,这个service可以无限地在后台运行,即使开始它的那个组件被销毁了。

      所以,service应该在完成工作后自己停止,通过调用stopSelf(),或另一个组件可以通过调用stopService()来停止它。

      简单说,就是: 

      一个应用组件,比如activity可以开启一个 service,通过调用startService() 方法并传递一个定制service和传递必要数据的intent对象。

      Service会在 onStartCommand()方法中获取这个对象。

      举个例子,一个activity需要把一些数据存储在一个网络上的数据库里,这个activity可以开启一个service,把要存储的数据通过一个startService()中的intent参数传递给service,service在 onStartCommand()方法中得到这个intent,建立网络连接并执行数据库事务。当事务处理完毕,service自己停止自己并销毁。

      注意:默认情况下,service运行在声明它的应用的同一个进程里面,而且在应用的主线程里面。

      所以,如果你的service需要执行一些繁重的或者阻塞性的工作,同时用户要和同一个应用中的activity进行交互,service会降低activity的性能。

      为了避免妨碍应用性能,你应该在service中新开启一个线程。

    可以继承两个类去创建一个started service

    Service

      这是所有service的基类。

      当你继承这个类时,比较重要的一点就是你需要创建一个新的线程,在里面做所有service的工作,因为这个service默认情况下会使用应用的主线程,这样会降低你的应用中正在运行的activity的性能。

    IntentService

      这是一个Service类的子类,它使用一个工作线程(worker thread)来处理所有的开启请求,一次一个。

      如果你不要求你的service同时处理多个请求的话,这是你最好的选择。

      你需要做的仅仅是实现 onHandleIntent()方法,它将接收到每一个start请求的intent,所以你可以做后台的工作。

     

    Extending the IntentService class

      因为多数的service不需要同时处理多个请求,所以你可以使用 IntentService来实现你自己的service。

      IntentService 做了如下的工作:

      1.创建一个默认的worker thread,与应用的主线程分离,处理所有传递给 onStartCommand()方法的intent。

      2.建立一个工作队列,一次传递一个intent给 onHandleIntent(),所以你永远不用担心多线程问题。

      3.当所有的start请求都被处理以后,停止service,所以你永远不必去调用 stopSelf()

      4.提供了onBind() 的默认实现,返回null。

      5.提供了 onStartCommand()的默认实现,把intent传向工作队列,然后传向 onHandleIntent() 的实现。

      所有的这些加起来,说明事实上你需要做的事情就仅仅是实现onHandleIntent()方法去做客户端提供的工作。

      当然,你还需要提供一个构造方法,它必须调用基类的IntentService(String)构造方法

      下面是一个实现例子:

    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 with * the 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)
             { } } } } }

      如果你决定覆写一些其他的回调方法,比如 onCreate()onStartCommand(), or onDestroy()请确定一定要调用基类的实现这样IntentService才能正确地管理worker线程的生命

      比如,onStartCommand() 必须返回默认的实现(这是有关intent被传递到 onHandleIntent()的)。

     

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
    {
        Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
        return super.onStartCommand(intent,flags,startId);
    }

     

      除了 onHandleIntent()还有仅一个方法中你不需要调用基类,那就是 onBind(),不过你仅仅在你的service允许绑定的时候需要实现它。

     

    Extending the Service class

      如果你需要你的service去执行多线程,而不是通过一个工作队列处理开始请求,你可以继承Service 来处理每一个intent。

      为了比较,下面是一个继承了Service类的实现,做的工作和上面继承IntentService的完全相同:

    直接继承Service类的实现
    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's
            // main 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();
        }
    }

      可以看到,与使用IntentService相比,我们需要做更多的工作,但是,因为你自己处理onStartCommand()的每一次调用,所以你可以同时执行多个请求。

      这个例子没有这样做,如果你想要同时处理多个请求,你可以为每个请求创建一个新的线程,然后立即执行它们,而不是等待上一个请求执行完毕再执行。

     

      注意到onStartCommand()方法必须返回一个整形,这个整形描述了系统应该如何继续被系统kill掉的service,

      返回值必须是下列常量之一:

    START_NOT_STICKY

      如果在 onStartCommand() 方法返回后系统将service销毁,不重建service,除非有pending intent被传递。

      这是最安全的一种选择,可以避免运行service在不必要的时候,和当你的应用可以重新开始未完成的工作的时候。

    START_STICKY

      如果在 onStartCommand() 方法返回后系统将service销毁,重建service,并且调用onStartCommand()方法,但是不重新传递上一个intent

      系统调用 onStartCommand()方法时传递一个null intent。

      除非有pending intent来开启这个service,在这种情况下,pending intent是被传递的。

      这种情况对于多媒体播放器(或者其他类似的service)比较适合,它们不执行命令,但是它们等待工作并无限执行。

    START_REDELIVER_INTENT

      如果在 onStartCommand() 方法返回后系统将service销毁,重建service,并且调用onStartCommand()方法,上一个intent将会被传递给service

      任何的pending intent将顺次被传递。

      这对于积极执行一项工作的service非常适合,因为它们应该被立即恢复,比如下载文件。

     

    Starting a Service

      你可以从一个activity或其他组件通过startService()方法来开始一个service,需要传递一个Intent对象来指定要开启的service。

      Android系统会调用service的onStartCommand()方法然后把Intent对象传递给它。

      比如:

    Intent intent = new Intent(this, HelloService.class);
    startService(intent);

     

      startService() 方法会立即返回,Android系统会调用service的onStartCommand()方法,如果service不是已经在运行,那么系统会先调用它的 onCreate()方法,然后调用onStartCommand()

      如果service没有同时提供绑定,那么传递给startService() 方法的intent对象是调用组件和service之间唯一的交流形式。

      但是,如果你想要service发送一个结果回来,那么开启service的客户可以为broadcast创建一个PendingIntent,(用getBroadcast()方法),然后把它作为开启service的intent传给service。这个service之后就可以使用这个broadcast来传递一个结果。

      多次的开启请求会导致多次的onStartCommand()方法被调用,然而,只需要一个停止的请求 (with stopSelf() or stopService()) 就可以将service停止。

     

    Stopping a service

      一个被开始的service必须管理自己的生命周期。

      即,系统不会停止或者销毁service(除非系统必须恢复一些内存),service将会在 onStartCommand() 方法返回之后一直持续运行。

      所以,service必须通过stopSelf()来停止自己,或者另一个组件通过stopService()来停止它。

      一旦通过 stopSelf() or stopService()方法发送了停止的请求,系统将会尽快销毁service。

      然而,如果你的service并行处理多个onStartCommand()请求,那么在你不应该在你处理完一个start请求之后stop这个service。因为你可能得到了一个新的start请求。(在第一个请求之后停止,有可能会终止第二个。)

      为了避免这个问题,你可以使用stopSelf(int) 来确保你要停止的请求永远基于最近开始的service。

      即是说,当你调用stopSelf(int) 时,你将start请求的ID  (the startId delivered toonStartCommand())传递过去。

      这样如果你的service在你的调用stopSelf(int)前得到一个新的start请求,由于ID不匹配,这个service不会被stop。

      注意:当service做完它的工作时,你的应用应该停掉它。这样可以避免系统资源浪费和电池能量消耗。

      如果有必要,其他组件可以通过stopService()来停止service。

      即便你允许绑定service,如果你的service有得到onStartCommand()方法的调用,你就永远必须自己停止它。

    参考资料

      API Guides:Services

      http://developer.android.com/guide/components/services.html

  • 相关阅读:
    UVA
    [CQOI2018] 社交网络
    UVA
    51nod 1314 定位系统
    51nod 1211 数独
    51nod 1392 装盒子
    51nod1253 Kundu and Tree
    51nod1313 完美串
    51nod1039 x^3 mod p
    51nod1369 无穷印章
  • 原文地址:https://www.cnblogs.com/mengdd/p/2978637.html
Copyright © 2020-2023  润新知