美文网首页编程Android开发经验谈Android技术知识
Android学习笔记2 四大组件之Service

Android学习笔记2 四大组件之Service

作者: RumbleTsc | 来源:发表于2016-07-08 21:09 被阅读684次

    四大组件中,我们最熟悉的而且最常用的应该是Activity了,它的主要作用是提供界面,用户可与之进行交互,那么如果有一些任务只需要在后台执行而不需要界面,那应该怎么办呢。今天总结归纳的是Service。

    一、Service概述
    二、Service的基本用法
       1.启动Service
       2.绑定Service
    三、Service生命周期
    四、Service的几点说明
    五、IntentService使用
    六、相关参考
    
    

    一、Service概述

    官方对Service服务的介绍:

    Service是一个可以在后台执行需要长时间运行的操作的应用组件,它不提供用户界面。其它组件可以启动一个Service,之后即使用户切换到别的应用里,这个Service也将继续在后台运行。此外,一个组件可以与一个Service绑定来与之交互,甚至可以执行IPC进程间通信。服务可以在后台执行很多任务,比如处理网络事务,播放音乐,文件读写或者与一个内容提供者交互,等等。

    Service主要有两种形式:启动状态和绑定状态。

    启动状态(Started)

    当一个应用组件比如activity通过调用startService()来启动一个服务的时候,服务便处于启动状态。一旦启动,服务可以在后台无限期地运行下去,即使当启动它的组件已经销毁。通常情况下,一个启动的service执行一个单一的操作并且不会返回任何结果给调用者。例如,服务可能通过网络下载或者上传一个文件,当操作完成,服务会自己停止。

    绑定状态(Bound)

    当一个应用组件通过调用bindService()来与一个服务绑定时,服务便处于绑定状态。一个绑定的服务提供了一个客户端-服务器端接口来允许组件与服务进行交互,发送请求,得到结果甚至通过IPC进程间通信来完成操作。只有当其它组件与服务绑定时,服务才会处于绑定状态。多个组件可以同时与服务绑定,但是当他们全部都解除绑定时,服务就会销毁。

    二、Service的基本用法

    对于Activity的使用,我们应该都比较熟悉了,一般是先新建一个继承Activity的自己的Activity,然后在里面写自己的逻辑,如果要启动一个Activity的话可以通过调用StartActivity()传入一个Intent对象来完成,在清单文件里进行Activity注册也是必不可少的一步。与之类似,Service基本用法也很简单,下面简单介绍启动Service的步骤,之后会有详细的介绍。

    启动Service

    1. 新建Service
    public class TestService extends Service {
    
        private final String TAG = "TestService";
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "---onCreate()---");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(TAG, "---onStartCommand()---");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i(TAG, "---onDestroy()---");
        }
    }
    
    1. 注册Service


      清单文件里注册Service.png

    3.启动Service

    点击按钮后启动Service

    从上面这张图可以看到,新建一个Intent对象并把它传给startService,这样就可以启动一个Service了,启动Service后如果想要停止它,可以使用stopService方法。

    停止Service.png

    绑定Service

    下面是组件与Service绑定的步骤。

    1. 首先我们修改一些之前的Service.
    public class TestService extends Service {
    
        private final String TAG = "TestService";
    
        //实例化"粘合剂" 可返回给与Service绑定的组件
        private MyBinder mMyBinder = new MyBinder();
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "---onCreate()---");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(TAG, "---onStartCommand()---");
            return super.onStartCommand(intent, flags, startId);
        }
    
        //绑定后调用此方法
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.i(TAG, "onBind");
            return mMyBinder;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i(TAG, "---onDestroy()---");
        }
    
        //这里执行任务
        public class MyBinder extends Binder {
            public void startTask() {
                Log.i(TAG, "Task starts...");
            }
        }
    }
    

    2.假设我们要在一个Activity里通过点击一个按钮来绑定Service,那么我们要先在Activity里新建一个ServiceConnection的实例。下面代码是在Activity里抽取出来的。

        private TestService.MyBinder mMyBinder;
    
        /**
         * 服务连接
         */
        private ServiceConnection mServiceConnection = new ServiceConnection() {
    
            /**
             * 当服务连接后 返回binder
             * @param name
             * @param binder
             */
            @Override
            public void onServiceConnected(ComponentName name, IBinder binder) {
                mMyBinder = (TestService.MyBinder) binder;
                mMyBinder.startTask();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
    
        };
    

    3.这样我们在Activity里点击一个按钮来绑定Service的时候,可以调用BindService来完成,详细如下图。

    绑定Service

    启动后的Service可以用stopService来停止服务,绑定后的Service可以用unbindService来取消绑定。

    取消绑定

    Service用法小结

    1. 上面的基本用法其实展示了Service最基本的用法,包括启动Service,停止Service,绑定Service以及取消绑定Service,Service里的逻辑很简单,实际上在平时的开发过程中,在后台执行时应该会比较复杂,考虑的东西也比较多。

    2. 启动Service的逻辑其实比较简单,就是新建一个Intent对象,然后调用startService方法把对象传进去,之后就可以启动了,停止的时候也是传一个Intent对象给stopService方法。

    3. 绑定Service的话逻辑较为复杂,这里我们是将Activity与Service建立绑定。我们可以看到几点注意事项:
      (1) 首先是在Service里,我们定义了一个继承Binder的子类,用来执行任务,Binder我觉得可以理解为"粘合剂",我们可以理解为它是其它组件和Service的之间的结合物,之后实例化这个Binder并在回调方法里返回这个Binder给绑定Service的组件,就可以通过它让组件控制Service了。
      (2) 然后是在Activity里实例化了一个ServiceConnection,并重写了onServiceConnected方法,这个方法会在建立连接后返回Service的Binder,然后通过Binder执行Service里的任务。
      (3) 绑定Service的时候,调用bindService方法,这里传入三个参数,一个是Intent对象,说明要与哪个Service绑定,一个是刚才的ServiceConnection实例,第三个参数是常量,我们这里传入BIND_AUTO_CREATE,表示绑定时是否自动创建Service。

    4. 销毁绑定的Service的时候只需要在使用unbindService方法时传入参数ServiceConnection实例即可。

    5. 如果既点击了Start Service按钮,又点击了Bind Service按钮,这样的话不管是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。

    三、Service生命周期

    Service的生命周期比Activity的简单很多,但是更加要引起重视,毕竟Service可能是在用户不知情的情况下在后台运行的。下面这张图很清楚地为我们展示了两种不同的方式,Service的生命周期。

    Paste_Image.png

    看这张图,我们可以初步对Service之前的几个回调方法有所了解,启动和绑定Service都会调用onCreate()方法来创建Service,如果是启动的话会调用onStartCommand()方法,如果是绑定的话会调用onBind()方法,当启动的Service停止后会调用onDestroy()方法销毁,绑定的Service在全部都解除绑定后调用onUnbind()方法,最后调用onDestroy()方法销毁。

    四、Service的几点说明

    1. A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.Service不是一个单独的进程,Service与它所在应用位于同一进程中。

    2. A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).Service不是一个线程,所以为了避免ANR错误(用户无响应),我们应该在Service里开启新的线程来处理耗时任务。

    3. 我们可以看到Service只是一个在后台运行的没有用户界面的组件,使用它做些耗时的任务时,是需要开启新线程的。这里如果有需要的话,可以详细去了解下IntentService这个类,它可以很方便地处理一些多线程问题。

    五、IntentService

    Service这个组件默认情况下仍然运行在应用的主线程中,所以如果我们要执行耗时或者阻塞操作,那么为了避免ANR,应该要在Service内创建一个新的线程。IntentService是Service类的一个子类,用来处理异步请求。

    下面是一个IntentService使用示例:

    //实现倒计时5秒的服务
    
    public class MyIntentService extends IntentService {
    
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         */
        public MyIntentService() {
            super("count down 5");
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.e("ssssss", "倒计时服务创建...");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
    
            long endTime = System.currentTimeMillis() + 5 * 1000;
    
            while (System.currentTimeMillis() < endTime) {
                synchronized (this) {
                    try {
                        wait(endTime - System.currentTimeMillis());
                    } catch (Exception e) {
                    } finally {
                        Log.e("ssssss", "倒计时结束...");
                    }
                }
            }
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.e("ssssss", "倒计时服务销毁...");
        }
    }
    
    
    

    与普通Service一样,我们可以通过startService(Intent)方法传递请求给IntentService。通过查看源码可知,IntentService在onCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象所对应的任务,这样以免事务处理阻塞主线程。执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service;否则执行下一个Intent请求所对应的任务。

    IntentService详解

    官方建议我们使用IntentService来完成异步请求的处理,那么IntentService内部具体都做了哪些东西呢?大概如下:

    1. 创建一个独立于应用主线程的新的线程来执行所有传递给onStartCommand()方法中的请求。

    2. 创建一个工作队列,一次传递一个请求到onHandleIntent()方法中。

    3. 当所有请求处理完成后,停止服务,不需要我们手动调用stopSelf()。

    4. 提供onBind()方法的默认实现,并且返回空。

    5. 帮我们实现了将请求从onStartCommand()传递到工作队列,然后传递到onHandleIntent()。

    为了对比地看出Service和IntentService在使用上的区别,下面展示一个使用Service的例子:

    
    public class HelloService extends Service {
      private Looper mServiceLooper;
      private ServiceHandler mServiceHandler;
    
      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() {
        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) {
          return null;
      }
    
      @Override
      public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      }
    }
    
    

    六、相关参考

    1. Service基本使用
      Android Service完全解析,关于服务你所需知道的一切(上)

    2. Service高级用法
      Android Service完全解析,关于服务你所需知道的一切(下)

    相关文章

      网友评论

      本文标题:Android学习笔记2 四大组件之Service

      本文链接:https://www.haomeiwen.com/subject/mrqkjttx.html