Android Service 和 IntentService

一.Service 的概念及作用

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

功能

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

二、声明Service

如同其他组件一样,想要使用Service,必须在清单文件中对其进行声明
声明方式是添加 < service > 元素作为 < application > 元素的子元素
例如:

<service 
     android:name="string"
     android:description="string resource"
         android:directBootAware=["true" | "false"]
         android:enabled=["true" | "false"]
         android:icon="drawable resource"
         android:label="string resource"
         android:permission="string"
      android:exported=["true" | "false"]
      android:isolatedProcess=["true" | "false"]
         >
</service>
属性 说明
name 服务类的完全限定名
description 对服务进行描述,属性值应为对字符串资源的引用,以便进行本地化
directBootAware 设置是否可以在用户解锁设备之前运行,默认值为“false”
enabled 设置是否可以由系统来实例化服务。< application >元素有自己的enabled属性,适用于包括服务在内的所有应用程序组件。要启用服务,< application >和< service >属性必须都为“true”(默认情况下都为true)。如果其中一个是“false”,则服务被禁用
icon 服务的图标,属性值应是对drawable资源的引用。如果未设置,则将使用应用程序图标
label 可以向用户显示的服务的名称,属性值应是对字符串资源的引用
permission 设定组件必须具有的权限,得以启动服务或绑定服务。如果startService(),bindService()或stopService()的调用者没有被授予此权限,则该方法将不会工作,并且Intent对象不会传递到服务中
process 用来运行服务的进程的名称。通常,应用程序的所有组件都运行在应用程序创建的默认进程中,它与应用程序包名具有相同的名称。 < application >元素的process属性可以为所有组件设置不同的默认值,但组件可以使用自己的进程属性覆盖默认值,从而允许跨多个进程扩展应用程序
isolatedProcess 设置该服务是否作为一个单独的进程运行,如果设置为true,此服务将在与系统其余部分隔离的特殊进程下运行,并且没有自己的权限,与它唯一的通信是通过服务API(绑定和启动
exported 设置其他应用程序的组件是否可以调用本服务或与其交互,如果可以,则为“true”。当值为“false”时,只有同一个应用程序或具有相同用户ID的应用程序的组件可以启动该服务或绑定到该服务。该属性的默认值取决于服务是否包含Intent filters。没有任何过滤器意味着它只能通过指定其确切的类名来调用,这意味着该服务仅用于应用程序内部使用(因为其他人不知道类名)。所以在这种情况下,默认值为“false”。 另一方面,如果存在至少一个过滤器,意味着该服务打算供外部使用,因此默认值为“true”

三.启动服务

启动服务的俩种方式

  • startService
  • bindService

startService

定义

使用startService()方法启用服务后,调用者与服务之间没有关连。调用者直接退出而没有调用stopService的话,Service会一直在后台运行。

使用场景:

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

启动流程

  • 首次启动Service调用 onCreate -> onStartCommand
  • 重复调用 startServer(),只会引起onStartCommand被多次调用

结束方式

调用Context.stopService()结束服务

bindService

定义

使用bindService()方法启用服务,调用者与服务绑定在一起了,调用者一旦退出,服务也就自动终止。

使用场景:

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

启动流程

  • 如果调用前服务没有被创建,则会引起onCreate()->onBind();

  • 如果已被创建但没有被绑定,则会引起onBind();

  • 如果服务已被绑定,则多次调用bindService并不会引起onCreate()和onBind()被多次调用

结束方式

  • 调用者退出,系统会自动调用服务到onUnbind()->onDestroy()方法。

  • 如果调用者希望与正在绑定的服务解除绑定,可以调用context.unbindService(),该方法会导致系统调用服务的onUnbind() –> onDestroy()方法。

注意:

  1. 如果第一次调用 startService(), 系统会 onCreate()-> onStartCommand();此时调用 bindService,只会onBind(),如果第一次调用bindService(), 系统会onCreate() -> onBind();此时调用startService, 只会onStart()

  2. 如果startbind都调用了, 那么一旦服务被绑定(只要成功调用了bindService, 不管是先startbind还是先bindstart, 就必须调用unbindServicestopService才能终止服务

4.异步服务IntentService

IntentService简介

IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:

  • Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;

  • Service也不是一个新线程,因此不应该在Service中直接处理耗时的任务,为此我们可以在Service中自己新建线程去执行耗时操作,不过Android系统引入了IntentService方便的解决了这个问题

IntentService特征

  • 会创建子线程来处理所有的Intent请求;
  • 会创建子线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题
  • 当操作完成时,IntentService会自动停止,我们不用手动停止 Service
  • 为Service的onBind()提供默认实现,返回null;
  • 省去了在 Service 中手动开线程的麻烦
public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: 创建了 ");
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: 启动 ");
 /*  
         * 这里返回状态有三个值,分别是:  
         * 1、START_STICKY:当服务进程在运行时被杀死,
         * 之后, 系统会尝试重新创建服务;  
         * 
         * 2、START_NOT_STICKY:当服务进程在运行时被杀死,
         * 并且没有新的Intent对象传递过来的话,系统将会把它置为started状态,  
         * 但是系统不会重新创建服务,直到startService(Intent intent)方法再次被               调用;  
         * 
         * 3、START_REDELIVER_INTENT:当服务进程在运行时被杀死,
         * 它将会在隔一段时间后自动创建,
         * 并且最后一个传递的Intent对象将会再次传递过来。  
         */
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: 绑定服务 ");
        return new MyBind();
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

            try {
                Thread.sleep(20000);
                Log.e(TAG, "onHandleIntent: 执行耗时操作");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy: 关闭服务");
    }

    public String getRiQi() {
        return "今天8月6号";
    }

    class MyBind extends Binder {
        public MyIntentService getMyService1() {
            return MyIntentService.this;
        }
    }
}
 bt_fw.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent=new Intent(MyServiceActivity.this,MyIntentService.class);
                startService(intent);
                bindService(intent,serviceConnection,BIND_AUTO_CREATE);
            }
        });

注意:一定要用startService 的方式启动服务,否则不会执行onHandleIntent 方法。

猜你喜欢

转载自blog.csdn.net/qq_26057629/article/details/81389706