Android中的服务在哪里,是一个可以在后台执行长
分类:美高梅网上注册平台

现实生活中的服务很常见,各式各样的人都在从事服务这个行业。但是Android中的服务呢?Android中的服务在哪里?我们什么时候需要服务呢?Android 中的服务怎么用?这就是这篇文章想要表述的内容。

onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行。

一、Service的定义

Service 是一个可以在后台执行长时间运行操作而不使用用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

服务是Android 实现程序后台运行的解决方案。看完这句话,马上就知道,服务在后台。没错,Android 中的服务是存在后台中的,它适合去执行哪些不需要与用户交互的但是还被要求长期运行的任务。比如,你在聊QQ的时候,喜欢听音乐,这时候你的音乐就是在后台挂着,即使你开了另外一个应用程序,当前的应用程序还是不会被关闭。 不过需要说明的是,Service服务不是运行在一个独立的程序中的,而是依赖于创建服务的这个应用程序中的。如果这个程序被杀死,服务也会停止。 前面说服务是在后台的。但是实际上服务不会自动开启线程,所有的服务都是在主线程中运行的。而我们知道主线程不能执行耗时的操作,否则会引起线程阻塞,所以我们需要在服务上创建子线程,由子线程去实现需要的具体工作。

Service和Activity通信

Activity通过binder来启动或停止service中的任务,并监听service中任务的进度。代码如下:
OnProgressListener

public interface OnProgressListener {
    void onProgress(int progress);  
}  

MyService

public class MyService extends Service {

    private final String TAG = "MyService";
    private int progress = 0;

    private MyBinder mBinder = new MyBinder();


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() executed");
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.d(TAG, "onStart() executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand() executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy() executed");
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind() executed");
        return super.onUnbind(intent);
    }

    class MyBinder extends Binder {
        /**
         * 更新进度的回调接口
         */
        private OnProgressListener onProgressListener;

        public void startDownload() {
            Log.d(TAG, "startDownload() executed");
            // 执行具体的下载任务
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                progress++;
                //进度发生变化通知调用方
                if (onProgressListener != null) {
                    onProgressListener.onProgress(progress);
                }
            }
        }

        public void stopDownload() {
            Log.d(TAG, "stopDownload() executed");
            // 执行具体的下载任务
        }

        /**
         * 注册回调接口的方法,供外部调用
         *
         * @param onProgressListener
         */
        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }
    }
}

MainActivity中

public class MainActivity extends AppCompatActivity {
    MyService.MyBinder myBinder = null;
    Button btn_start,btn_stop;
    private String Tag = "MyService";
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (MyService.MyBinder) service;
            myBinder.setOnProgressListener(new OnProgressListener() {
                @Override
                public void onProgress(int progress) {
                    Log.i(Tag,"progress: "+progress);
                }
            });
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_start = (Button)findViewById(R.id.btn_start);
        btn_stop = (Button)findViewById(R.id.btn_stop);
        Intent bindIntent = new Intent(this, MyService.class);
        bindService(bindIntent, connection, BIND_AUTO_CREATE);
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myBinder.startDownload();
            }
        });
        btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myBinder.stopDownload();
            }
        });
    }
}

二、Service的种类

  1. 启动服务,当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。

  2. 绑定服务, 当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

美高梅网上注册平台,注意:服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。 这意味着,如果服务将执行任何 CPU 密集型工作或阻止性操作,则应在服务内创建新线程来完成这项工作。通过使用单独的线程,可以降低发生“应用无响应”(ANR) 错误的风险,而应用的主线程仍可继续专注于运行用户与 Activity 之间的交互。

因为我们知道Service是依赖于应用程序的,应用程序终止了,服务也终止了。所以了解Service的生命周期非常重要。

美高梅4858app,bindService和startService的区别

  1. 生命周期的区别:
    startService,【onCreate()- >onStartCommand()->startService()->onDestroy()】
    补充说明:其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了;
    bindService(),【onCreate()->onBind()->onUnbind()->onDestroy()】
    补充说明:传递给bindService()的Intent对象会传递给onBind(),传递给unbindService()的Intent对象会传递给onUnbind()方法。调用顺序为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
  2. 调用者和服务者之间的关系:
    startService()的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行。
    bindService()调用者和绑定者绑在一起,调用者一旦退出服务也就终止了。
    注意:BroadcastReceiver只能通过startService启动Service,因为广播本身生命周期很短,bind的话没有意义。
  3. 关于多次调用:
    多次调用startService,该Service只能被创建一次,即该Service的onCreate方法只会被调用一次。但是每次调用startService,onStartCommand方法都会被调用。Service的onStart方法在API 5时被废弃,替代它的是onStartCommand方法。
    第一次执行bindService时,onCreate和onBind方法会被调用,但是多次执行bindService时,onCreate和onBind方法并不会被多次调用,即并不会多次创建服务和绑定服务。
  4. 既使用startService又使用bindService的情况
    如果一个Service又被启动又被绑定,则该Service会一直在后台运行。首先不管如何调用,onCreate始终只会调用一次。对应startService调用多少次,Service的onStartCommand方法便会调用多少次。Service的终止,需要unbindService和stopService同时调用才行。不管startService与bindService的调用顺序,如果先调用unbindService,此时服务不会自动终止,再调用stopService之后,服务才会终止;如果先调用stopService,此时服务也不会终止,而再调用unbindService或者之前调用bindService的Context不存在了(如Activity被finish的时候)之后,服务才会自动停止。
    那么,什么情况下既使用startService,又使用bindService呢?
    如果你只是==想要启动一个后台服务长期进行某项任务同时还想要与正在运行的Service取得联系,那么有两种方法:一种是使用broadcast,另一种是使用bindService。前者的缺点是如果交流较为频繁,容易造成性能上的问题,而后者则没有这些问题。因此,这种情况就需要startService和bindService一起使用了。
    另外,如果你的服务只是公开一个远程接口,供连接上的客户端(Android的Service是C/S架构)远程调用执行方法,这个时候你可以不让服务一开始就运行,而只是bindService,这样在第一次bindService的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是远程服务,那么效果会越明显(当然在Servcie创建的是偶会花去一定时间,这点需要注意)
  5. 销毁 service
    Bind Service -> Unbind Service
    Start Service -> Stop Service
    Bind Service + Start Service -> Unbind Service + Stop Service(无顺序区别)
    ==注意点==
    onServiceDisconnected 会在程序意外退出时才会调用

三、生命周期

美高梅网上注册平台 1

service_lifecycle

  • onStartCommand()
      当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果您实现此方法,则在服务工作完成后,需要通过调用 stopSelf() 或 stopService() 来停止服务。(如果只想提供绑定,则无需实现此方法。)

  • onStartCommand有三种返回值:
      START_STICKY:sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序"粘"在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
      START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
      START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

  • onBind()
      当另一个组件想通过调用 bindService() 与服务绑定时,系统将调用此方法。在此方法的实现中,必须通过返回 IBinder 提供一个接口,供客户端用来与服务进行通信。但如果并不希望允许绑定,则应返回 null。

  • onCreate()
      首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或 onBind() 之前)。如果服务已在运行,则不会调用此方法。

  • onDestroy()
      当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。

美高梅网上注册平台 2service的生命周期

参考

startService与bindService的区别

实验

1.startService * 1

09-26 09:34:37.679 28439-28439/com.tang.servicedemo D/MyService: onCreate
09-26 09:34:37.679 28439-28439/com.tang.servicedemo D/MyService: onStartCommand

2.startService * 3

09-26 09:36:39.449 30544-30544/com.tang.servicedemo D/MyService: onCreate
09-26 09:36:39.449 30544-30544/com.tang.servicedemo D/MyService: onStartCommand
09-26 09:36:40.649 30544-30544/com.tang.servicedemo D/MyService: onStartCommand
09-26 09:36:41.539 30544-30544/com.tang.servicedemo D/MyService: onStartCommand

onCreate方法只执行了一次,onStartCommand方法会执行多次

3.startService -> stopService

09-26 09:38:37.529 32366-32366/com.tang.servicedemo D/MyService: onCreate
09-26 09:38:37.529 32366-32366/com.tang.servicedemo D/MyService: onStartCommand
09-26 09:38:40.549 32366-32366/com.tang.servicedemo D/MyService: onDestroy

4.bindService * 1

09-26 09:40:20.989 1630-1630/com.tang.servicedemo D/MyService: onCreate
09-26 09:40:20.989 1630-1630/com.tang.servicedemo D/MyService: onBind
09-26 09:40:21.009 1630-1630/com.tang.servicedemo D/MyService: MainActivity onServiceConnected

服务绑定成功会调用 onServiceConnected方法

5.bindService * 3

09-26 09:41:54.899 3363-3363/com.tang.servicedemo D/MyService: onCreate
09-26 09:41:54.899 3363-3363/com.tang.servicedemo D/MyService: onBind
09-26 09:41:54.909 3363-3363/com.tang.servicedemo D/MyService: MainActivity onServiceConnected

onCreate 和 onBind 方法均只执行一次

6.bindService -> unbindService

09-26 09:44:18.179 5184-5184/com.tang.servicedemo D/MyService: onCreate
09-26 09:44:18.179 5184-5184/com.tang.servicedemo D/MyService: onBind
09-26 09:44:18.179 5184-5184/com.tang.servicedemo D/MyService: MainActivity onServiceConnected
09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onUnbind
09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onDestroy

7.startService -> bindService -> stopService -> unbindService

09-26 09:48:51.689 9519-9519/com.tang.servicedemo D/MyService: onCreate
09-26 09:48:51.689 9519-9519/com.tang.servicedemo D/MyService: onStartCommand
09-26 09:48:53.119 9519-9519/com.tang.servicedemo D/MyService: onBind
09-26 09:48:53.119 9519-9519/com.tang.servicedemo D/MyService: MainActivity onServiceConnected
09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onUnbind
09-26 09:48:57.399 9519-9519/com.tang.servicedemo D/MyService: onDestroy
  1. startService -> bindService -> unbindService -> stopService

    09-26 09:50:18.259 10631-10631/com.tang.servicedemo D/MyService: onCreate 09-26 09:50:18.259 10631-10631/com.tang.servicedemo D/MyService: onStartCommand 09-26 09:50:20.279 10631-10631/com.tang.servicedemo D/MyService: onBind 09-26 09:50:20.289 10631-10631/com.tang.servicedemo D/MyService: MainActivity onServiceConnected 09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onUnbind 09-26 09:50:24.919 10631-10631/com.tang.servicedemo D/MyService: onDestroy

  2. startService -> bindService -> unbindService -> -> bindService -> unbindService -> stopService

    09-26 09:59:40.519 19320-19320/com.tang.servicedemo D/MyService: onCreate 09-26 09:59:40.519 19320-19320/com.tang.servicedemo D/MyService: onStartCommand 09-26 09:59:42.379 19320-19320/com.tang.servicedemo D/MyService: onBind 09-26 09:59:42.389 19320-19320/com.tang.servicedemo D/MyService: MainActivity onServiceConnected 09-26 09:59:42.389 19320-19320/com.tang.servicedemo D/MyService: android.os.Binder@b10bdcd0 09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onUnbind 09-26 09:59:47.569 19320-19320/com.tang.servicedemo D/MyService: MainActivity onServiceConnected 09-26 09:59:47.569 19320-19320/com.tang.servicedemo D/MyService: android.os.Binder@b10bdcd0 09-26 09:59:53.279 19320-19320/com.tang.servicedemo D/MyService: onDestroy

onCreate 、onBind 和 onUnbind 方法均只执行一次,onServiceConnected会执行多次,而且返回的对象是同一个对象

  1. MainActivity startService -> SecondActivity startService -> ThirdActivity startService -> ThirdActivity stopService

    09-26 10:33:02.239 12783-12783/com.tang.servicedemo D/MyService: onCreate 09-26 10:33:02.239 12783-12783/com.tang.servicedemo D/MyService: onStartCommand 09-26 10:33:05.719 12783-12783/com.tang.servicedemo D/MyService: onStartCommand 09-26 10:33:09.689 12783-12783/com.tang.servicedemo D/MyService: onStartCommand 09-26 10:33:13.659 12783-12783/com.tang.servicedemo D/MyService: onDestroy

只要调用 stopService 就会停止服务

  1. MainActivity bindService -> SecondActivity bindService -> ThirdActivity bindService -> ThirdActivity unbindService -> SecondActivity unbindService -> MainActivity unbindService

    09-26 10:35:54.819 15553-15553/com.tang.servicedemo D/MyService: onCreate 09-26 10:35:54.819 15553-15553/com.tang.servicedemo D/MyService: onBind 09-26 10:35:54.819 15553-15553/com.tang.servicedemo D/MyService: MainActivity onServiceConnected 09-26 10:35:54.819 15553-15553/com.tang.servicedemo D/MyService: android.os.Binder@b106f680 09-26 10:35:57.929 15553-15553/com.tang.servicedemo D/MyService: SecondActivity onServiceConnected 09-26 10:35:57.929 15553-15553/com.tang.servicedemo D/MyService: android.os.Binder@b106f680 09-26 10:36:00.749 15553-15553/com.tang.servicedemo D/MyService: ThirdActivity onServiceConnected 09-26 10:36:00.749 15553-15553/com.tang.servicedemo D/MyService: android.os.Binder@b106f680 09-26 09:44:19.689 5184-5184/com.tang.servicedemo D/MyService: onUnbind 09-26 10:36:09.809 15553-15553/com.tang.servicedemo D/MyService: onDestroy

onCreate 、 onBind 和 onUnbind 方法只会调用一次,onServiceConnected会调用多次,只有所有的Activity都解绑了,服务才会停止。

Service的生命周期有两种:

注意

  1. 调用 bindService 绑定到Service的时候,保证在某处调用 unbindService 解除绑定(尽管Activity被finish的时候绑定会自动解除,并且Service会自动停止)。

  2. 使用 startService 启动服务之后,一定要使用stopSelf()停止服务或另外的组件调用stopService()停止服务,不管是否使用bindService。 但是,如果服务同时处理多个 onStartCommand() 请求,则不应在处理完一个启动请求之后停止服务,因为可能已经收到了新的启动请求(在第一个请求结束时停止服务会终止第二个请求)。为了避免这一问题,可以使用 stopSelf(int) 确保服务停止请求始终基于最近的启动请求。也就说,在调用 stopSelf(int) 时,传递与停止请求的 ID 对应的启动请求的 ID(传递给 onStartCommand() 的 startId) 。然后,如果在您能够调用 stopSelf(int) 之前服务收到了新的启动请求, ID 就不匹配,服务也就不会停止。

  3. 同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止。

  4. 当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

  5. 在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么应当使用 onStartCommand 而不是 onStart。

  6. Android 5.0一出来后,其中有个特性就是Service Intent must be explitict,也就是说从Lollipop开始,service服务必须采用显示方式启动。

android源码是这样写的(源码位置:sdk/sources/android-21/android/app/ContextImpl.java)

 private void validateServiceIntent(Intent service) {
        if (service.getComponent() == null && service.getPackage() == null) {
            if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
                IllegalArgumentException ex = new IllegalArgumentException(
                        "Service Intent must be explicit: " + service);
                throw ex;
            } else {
                Log.w(TAG, "Implicit intents with startService are not safe: " + service
                        + " " + Debug.getCallers(2, 3));
            }
        }
    }

解决办法:

Intent mIntent = new Intent();
mIntent.setAction("XXX.XXX.XXX");//你定义的service的action
mIntent.setPackage(getPackageName());//这里你需要设置你应用的包名
context.startService(mIntent);

关于Service生命周期还有一张比较易懂的图:

美高梅网上注册平台 3

  1. Started Service的生命周期:

扩展

本文由美高梅网上注册平台发布于美高梅网上注册平台,转载请注明出处:Android中的服务在哪里,是一个可以在后台执行长

上一篇:工厂模式UML.png,工厂模式使用工厂方法代替 下一篇:  保存在内存中的数据是瞬时数据,文件存储
猜你喜欢
热门排行
精彩图文