zoukankan      html  css  js  c++  java
  • Android Service介绍

    本文主要介绍Service的概念及作用、使用(包括长时间运行的服务、应用内交互的服务、应用间交互的服务的分别举例、生命周期、使用场景)、特殊的Service

    示例代码见ServiceDemo示例APK见:TrineaAndroidDemo.apk

     
    1、概念及作用

    由于ANR对Activity和BroadcastReceiver响应时间的限制(Activity对事件响应不超过5秒,BroadcastReceiver执行不超过10秒),使得在其中都不适合执行较耗时操作,这样像网络、数据库、复杂计算这类耗时操作的执行就需要一个组件来承担。Service作为Android四大组件之一,其功能之一就是耗时操作的执行,主要功能如下:

    a. 执行需要长时间运行的操作,这个操作不与用户进行交互,如网络下载、大文件I/O、复杂计算。
    b. 应用内或应用间数据通信,Android每个应用程序都在自己的dalvik虚拟机中运行,一个应用是不允许访问其他应用的内存信息的,为此Android引入了Content Provider在不同应用间共享数据,BroadcastReceiver广播信息给不同应用程序,但Content Provider更多用于数据的共享,BroadcastReceiver广播的信息会被所有应用接收较耗费系统资源,对于两个应用间动态的进行交互还需要通过Service来完成。

    2、使用
    (1) startService启动不可进行交互的Service

    a. 示例代码及介绍

    Service示例
    public class MyService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            Toast.makeText(this, "Service Create", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onDestroy() {
            Toast.makeText(this, "Service Destroty", Toast.LENGTH_SHORT).show();
            super.onDestroy();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Toast.makeText(this, "Service Start", Toast.LENGTH_SHORT).show();
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }

    服务都必须在AndroidManifest.xml文件中注册<service android:name=".MyService"/>,在Activity中定义对象private Intent myServiceIntent = new Intent(this, MyService.class);在onCreate函数中startService(myServiceIntent)启动服务; onDestroy函数中stopService(myServiceIntent)关闭服务;

    b. 生命周期
    通过startService启动服务,若服务未启动,会先执行onCreate函数(若服务已启动则不执行此函数),再执行onStartCommand函数。由此可知多次调用startService传入相同参数不会启动多个服务(onStartCommand函数会执行多次),所以最终只需要调用一次stopService或stopSelf函数停止服务;我们可以将service的处理逻辑放入onStartCommand函数中。服务一直运行,在程序退出后服务也不会停止,直到stopService或stopSelf函数被调用,当然可能被系统回收。

    对于onStartCommand的返回值,若返回START_STICKY表示服务通过显式调用启动或停止,若返回START_NOT_STICKY orSTART_REDELIVER_INTENT表示服务仅在有请求发送过来处理时才处于运行状态。

    c. 使用场景

    因为这种方式Service无法与外部进行方便的动态交互,所以适合做后台服务,如网络下载(用户通过Intent传入Url到Service,推荐使用IntentService).

    (2) bindService启动的Service应用内交互

    a. 示例代码及介绍

    在上面的方式中Context可以通过Intent向Service传入简单的信息,但是如果希望调用Service的接口进行操作或是获取Service的属性则无法实现,这里我们可以通过bindService实现,如下先定义自己的服务

    自定义Service
    public class MyService extends Service {
    
        private int      count;
        private MyBinder myBinder = new MyBinder();
    
        @Override
        public void onCreate() {
            Toast.makeText(this, "Service onCreate", Toast.LENGTH_SHORT).show();
            count = 0;
            super.onCreate();
        }
    
        @Override
        public void onDestroy() {
            Toast.makeText(this, "Service onDestroy", Toast.LENGTH_SHORT).show();
            super.onDestroy();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
    
        /**
         * 服务被绑定时调用
         * 返回值用于让调用者和服务通信,传入ServiceConnection的public void onServiceConnected(ComponentName name, IBinder service)函数第二个参数
         */
        @Override
        public IBinder onBind(Intent intent) {
            return myBinder;
        }
    
        public int getCount() {
            return count;
        }
    
        public int increaseCount() {
            return ++count;
        }
    
        public int decreaseCount() {
            return --count;
        }
    
        public class MyBinder extends Binder {
    
            MyService getService() {
                return MyService.this;
            }
        }
    }

    从上可以看出我们重写onBind函数并返回自己的Binder用于调用者和服务之间通信。下面我们在调用者中进行调用

    定义自己的Service、Intent、ServiceConnection对象
    private MyService         myService;
    private Intent            myServiceIntent;
    private ServiceConnection con = new ServiceConnection() {
    
                                      /**
                                       * 服务所在进程被kill或是crash时系统调用,而不是unbindService时调用
                                       */
                                      @Override
                                      public void onServiceDisconnected(ComponentName name) {
                                          Toast.makeText(getApplicationContext(), "Service disconnect",
                                                         Toast.LENGTH_SHORT).show();
                                      }
    
                                      /**
                                       * 服务连接时调用,若已经连接不进行调用
                                       */
                                      @Override
                                      public void onServiceConnected(ComponentName name, IBinder service) {
                                          myService = ((MyBinder)service).getService();
                                          Toast.makeText(getApplicationContext(), "Service Connect", Toast.LENGTH_SHORT).show();
                                      }
                                  };

    接着调用bindService(myServiceIntent, con, Context.BIND_AUTO_CREATE);绑定服务,绑定成功返回true。这时会执行ServiceConnection对象的onServiceConnected函数为myService变量赋值。接着我们就可以通过myService.increaseCount();操作Service的属性,myService.getCount()获得Service的属性,这样我们就成功和Service进行了通信。在不需要通信时通过unbindService(con);解除服务绑定。

    b. 生命周期
    通过bindService绑定服务,若服务未启动,会先执行Service的onCreate函数,再执行onBind函数,最后执行ServiceConnection对象的onServiceConnected函数。若服务已启动但尚未绑定,先执行onBind函数,再执行ServiceConnection对象的onServiceConnected函数。若服务已绑定成功,则直接返回。这里不会自动调用onStartCommand函数。

    通过unbindService解除绑定服务,若已绑定成功,会先执行Service的onUnbind函数,再执行onDestroy函数,注意这里不会执行ServiceConnection对象的onServiceDisconnected函数,因为该函数是在服务所在进程被kill或是crash时被调用。若服务尚未绑定系统会报服务尚未注册异常,我们可以通过如下代码解决

    if (myService != null) {
        unbindService(con);
        myService = null;
    }

    与startService启动的Service不同,若服务通过bindService启动并且没有通过startService启动过后,则在连接断开时服务就会自动解绑(onUnbind)并终止(onDestroy),而在调用者(Activity)退出后会自动断开连接,所以这时服务会自己解绑并终止。若存在某个组件绑定了该服务,则调用该服务的stopService不会停止服务

    c. 使用场景

    应用内通信,如音乐播放器,在服务中控制播放器的播放、暂停、停止,在Activity中通过对服务操作控制播放器。


    (3) bindService启动的Service应用间交互——AIDL

    在Android AIDL应用间交互中 详细介绍见Android AIDL交互

    通过上面的三个例子我们可以看出Context.startService()Context.bindService()的区别

    a. bindService启动的Service可以和Context进行交互,而startService启动的Service不可以交互,因而使用场景也不同

    b. 执行的生命周期不同

    3、特殊的Service

    (1). 异步服务IntentService

    默认Service是运行在主线程内的 ,如果在Service内运行一个耗时操作就会阻塞主线程,可能导致ANR,为此我们可以在Service中自己新建线程去执行耗时操作,不过Android系统引入了IntentService方便的解决了这个问题, IntentService会启动一个工作线程去完成用户onHandleIntent中定义的操作,需要注意的是对于同一个IntentService的多次请求(startService调用),在同一个线程中处理,一次只会执行一个请求的onHandleIntent函数。对于不同IntentService的同时请求,在不同的线程中处理,所以每个请求的onHandleIntent函数可以并发执行。示例代码如下:

    IntentService示例
    public class MyIntentService extends IntentService {
    
        public MyIntentService(){
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            try {
                System.out.println("IntentService1 Begin Sleep. " + "Thread name: " + Thread.currentThread().getName()
                                   + ", Thread Id: " + Thread.currentThread().getId());
                Thread.sleep(3000);
                System.out.println("IntentService1 End. ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    在AndroidManifest.xml文件中注册服务<service android:name=".MyIntentService"/>,在Activity中定义service对象private Intent myIntentServiceIntent = new Intent(ServiceDemo.this, MyIntentService.class);在onCreate函数中startService(myIntentServiceIntent)启动服务;

    从上面我们可以看出
    a. IntentService只需要重定义onHandleIntent函数并定义一个无参构造函数(xml中服务注册初始化时使用)即可。
    b. IntentService服务在onHandleIntent执行结束后会自动关闭。

    IntentService和普通Service的区别如下
    a. 普通Service运行在主线程中,IntentService运行在一个工作线程中不会阻塞主线程。
    b. 普通Service需要手动调用停止接口,IntentService自动停止。
    c. IntentService的onStartCommand函数根据mRedelivery属性值返回START_REDELIVER_INTENT或START_NOT_STICKY,而普通Service自定义返回。

    参考:
    http://developer.android.com/reference/android/app/Service.html

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

    http://developer.android.com/reference/android/app/IntentService.html

  • 相关阅读:
    正则表达式
    [创业指南]给海归技术创业兄弟的九个忠告
    about avast
    设计模式Hibernate
    job desc
    把INT转换成2进制等
    微服务调用跟踪
    Redis 分布式锁实现
    jquery中的$.ajax()方法
    订单从ftp写入到b2b
  • 原文地址:https://www.cnblogs.com/trinea/p/2699856.html
Copyright © 2011-2022 走看看