当前位置:   article > 正文

Android基础笔记:(2)四大组件 Service 详解【更新结束】_提交对android的四大组件service的认知

提交对android的四大组件service的认知

目录

一、Service简介

二、Service分类

1、Started Service

2、Bound  Service

 3、启动Service回调的方法

4、通过代码还原Service生命周期

三、使用IntentService

  1、为什么使用IntentService ?

  2、 IntentService服务为什么可以自动创建线程?为什么可以自动结束服务?


一、Service简介

        Service是Android的四大组件之一。

作用

        后台长期处理耗时的逻辑。

Service与Activity的区别

        不同点:Service与Activity功能大抵相同,区别在于Service不存在UI界面,Service在后台运行,不能与用户进行交互功能。

        相同点:都需要在清单文件中注册,且都有生命周期。

Service的特点

        (1)、在后台运行,即使应用退出,也不会停止服务,只有在杀死APP进程时,才会停止服务。

        (2)、Service运行在主线程中。所以,当我们执行一些耗时的操作时,可以在服务中创建子线程来处理耗时的操作。

        (3)、Service应用广泛,例如:音乐播放,下载文件等。

更多关于Service的内容详见官方文档:服务概览  |  Android 开发者  |  Android Developers

 对于Service服务我们都不陌生,它大概在我们手机中是这样的。

接下来开始学习如何使用Service服务吧。

二、Service分类

按照启动方式可以分为:

1、Started Service

        当组件通过调用 startService() 方法启动 Service ,这时,Service处于启动状态,可以在后台无限期的运行,只有自身调用stopSelf() 方法 或者 其他组件调用 stopService() 方法才会停止Service。

2、Bound  Service

        当组件通过调用 bindService() 方法绑定 Service,这时,Service处于绑定状态,多个组件可以绑定在一个Service上,当绑定Service的所有组件解绑之后,该Service被销毁。

        两种启动方式的生命周期如下:

 3、启动Service回调的方法

startService():启动服务

        (手动调用)不受调用组件的控制,可以在后台无限期的运行。

bindService():绑定服务

        (手动调用)将多个组件与服务绑定在一块,随着组件的消亡而消亡。

onCreate():创建服务

        (自动调用)无论是开启服务还是绑定服务,最开始的回调函数肯定是onCreate(),当第一次创建Service的时候调用该方法,多次调用startService()方法不会重复调用onCreate() 方法。适合做一些初始化操作。

onStartcommand():重复开始服务

        (自动调用)当多次执行startService()方法的时候,onStartcommand()都会执行。

onBind():绑定服务

        (自动调用)当一个组件想要通过bindService()绑定service时,系统会回调该方法。该方法需要实现一个接口,通过返回IBinder对象实现用户通信。若不需要绑定service则返回null,否则必须实现。

unbindService():解绑服务【相对于某个组件来说】

        (手动调用)当组件想要与该服务解绑时调用,只有在所有用户解绑之后才会调用onUnbind()回调函数。

onUnbind():解绑服务【相对于服务来说】

        (自动调用)当所有捆绑服务的组件解绑之后,系统自动调用onUnbind()函数,将服务解绑。

onDestroy():销毁服务

        (自动调用)当Service调用这个函数的时候,这个服务就销毁停止了。下次在用的时候只能执行onCreate()函数进行创建。

stopService():结束服务

        (手动调用)其他组件通过调用该函数,将以startService()启动的Service停止掉。

stopSelf():结束服务

        (手动调用)当前Service调用此方法来终结自己。

4、通过代码还原Service生命周期

        案例:在MainActivity中定义四个按钮,分别是:启动服务,绑定服务,解绑与结束服务。点击相应的按钮完成相应的功能。

activity_main.xml代码

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context=".MainActivity"
  7. android:orientation="vertical">
  8. <Button
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:text="启动服务"
  12. android:id="@+id/start_button"/>
  13. <Button
  14. android:layout_width="match_parent"
  15. android:layout_height="wrap_content"
  16. android:text="绑定服务"
  17. android:id="@+id/bind_button"/>
  18. <Button
  19. android:layout_width="match_parent"
  20. android:layout_height="wrap_content"
  21. android:text="解除绑定"
  22. android:id="@+id/unbind_button"/>
  23. <Button
  24. android:layout_width="match_parent"
  25. android:layout_height="wrap_content"
  26. android:text="结束服务"
  27. android:id="@+id/stop_button"/>
  28. <TextView
  29. android:id="@+id/text"
  30. android:text="XXXXXX"
  31. android:layout_height="match_parent"
  32. android:layout_width="match_parent"
  33. android:textSize="28sp"/>
  34. </LinearLayout>

AndroidManifest.xml

注册服务:<service>

        其中有两个属性:

1、android:enabled:表示指定的Service能否被实例化,true表示能,false表示不能。

2、android:exported:表示指定的其他组件能否调用Service或者与其交互,true表示能,false表示不能。当该值为false时,只有同应用的组件或者具有相同用户ID的程序才能启动或者绑定到Service 。

  1. <!-- 注册服务 -->
  2. <service android:name=".MyService"/>

MainActivity.java

  1. package com.example.servicedemo1;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.ComponentName;
  4. import android.content.Intent;
  5. import android.content.ServiceConnection;
  6. import android.os.Bundle;
  7. import android.os.IBinder;
  8. import android.util.Log;
  9. import android.view.View;
  10. import android.widget.Button;
  11. import android.widget.TextView;
  12. import android.widget.Toast;
  13. public class MainActivity extends AppCompatActivity {
  14. private Button start_button;
  15. private Button bind_button;
  16. private Button unbind_button;
  17. private Button stop_button;
  18. private TextView text;
  19. private static final String TAG1 = "serviceConnection";
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(R.layout.activity_main);
  24. //代码重构
  25. extracted();
  26. //创建Intent对象,用于服务相关操作
  27. Intent intent = new Intent(MainActivity.this, MyService.class);
  28. //启动服务
  29. startListener(intent);
  30. //绑定服务
  31. bindORunbindListener(intent);
  32. //结束服务
  33. stopListener(intent);
  34. }
  35. /**
  36. * 代码重构,获取控件
  37. */
  38. private void extracted() {
  39. start_button = this.findViewById(R.id.start_button);
  40. bind_button = this.findViewById(R.id.bind_button);
  41. unbind_button = this.findViewById(R.id.unbind_button);
  42. stop_button = this.findViewById(R.id.stop_button);
  43. text = this.findViewById(R.id.text);
  44. }
  45. /**
  46. * 点击启动服务按钮事件
  47. * @param intent
  48. */
  49. private void startListener(Intent intent) {
  50. //点击“启动服务”的事件处理
  51. start_button.setOnClickListener(new View.OnClickListener() {
  52. @Override
  53. public void onClick(View v) {
  54. //startService():启动服务
  55. startService(intent);
  56. //将结果显示到页面
  57. text.setText("我已经启动服务啦!");
  58. }
  59. });
  60. }
  61. /**
  62. * 点击绑定与解绑服务的按钮事件
  63. *
  64. * @param intent
  65. */
  66. private void bindORunbindListener(Intent intent) {
  67. ServiceConnection serviceConnection = new ServiceConnection() {
  68. @Override
  69. public void onServiceConnected(ComponentName name, IBinder service) {
  70. Log.e(TAG1,"调用onServiceConnected");
  71. }
  72. @Override
  73. public void onServiceDisconnected(ComponentName name) {
  74. Log.e(TAG1,"调用onServiceDisconnected");
  75. }
  76. };
  77. 点击“绑定服务”的事件处理
  78. bind_button.setOnClickListener(new View.OnClickListener() {
  79. @Override
  80. public void onClick(View v) {
  81. //bindService():绑定服务
  82. bindService(intent,serviceConnection,BIND_AUTO_CREATE);
  83. text.setText("我已经绑定服务啦!");
  84. }
  85. });
  86. 点击“解除绑定”的事件处理
  87. unbind_button.setOnClickListener(new View.OnClickListener() {
  88. @Override
  89. public void onClick(View v) {
  90. //unbindService():解绑服务
  91. unbindService(serviceConnection);
  92. text.setText("解除绑定服务啦!");
  93. }
  94. });
  95. }
  96. /**
  97. * 结束服务按钮事件
  98. */
  99. private void stopListener(Intent intent) {
  100. //点击“结束服务”的事件处理
  101. stop_button.setOnClickListener(new View.OnClickListener() {
  102. @Override
  103. public void onClick(View v) {
  104. //stopService():结束服务
  105. stopService(intent);
  106. text.setText("服务已经结束啦!");
  107. }
  108. });
  109. }
  110. }

MyService.java

  1. package com.example.servicedemo1;
  2. import android.app.Service;
  3. import android.content.Intent;
  4. import android.os.IBinder;
  5. import android.util.Log;
  6. public class MyService extends Service {
  7. private static final String TAG = "MyService";
  8. @Override
  9. public void onCreate() {
  10. super.onCreate();
  11. Log.d(TAG, "创建服务 ——> onCreate()");
  12. }
  13. @Override
  14. public IBinder onBind(Intent intent) {
  15. Log.d(TAG, "绑定服务 ——> onBind()");
  16. return null;
  17. }
  18. @Override
  19. public int onStartCommand(Intent intent, int flags, int startId) {
  20. Log.d(TAG, "重启服务(首次为启动) ——> onStartCommand()");
  21. return super.onStartCommand(intent, flags, startId);
  22. }
  23. @Override
  24. public boolean onUnbind(Intent intent) {
  25. Log.d(TAG, "解绑服务 ——> onUnbind()");
  26. return super.onUnbind(intent);
  27. }
  28. @Override
  29. public void onDestroy() {
  30. super.onDestroy();
  31. Log.d(TAG, "销毁服务 ——> onDestroy()");
  32. }
  33. }

结果:

        (1)、第一次点击“启动服务”时:onCreate() ——> onStartCommand()

        (2)、再次点击“启动服务”时:onStartCommand()

        (3)、点击“启动服务”后又点击“绑定服务”时:onCreate()  ——>  onBind()

        (4)、点击“解绑服务”时:onUnbind()

        (5)、点击“结束服务”时:onDestroy()

如图:

三、使用IntentService

  1、为什么使用IntentService ?

        由于Service不会专门启动一个线程执行一些耗时的操作,导致所有的操作都是在主线程中进行的,稍不留神就会造成ANR异常,所以需要手动来创建一个线程可供Service执行耗时操作。

        另一个原因就是:Service启动后不会停止,只有在自身调用 stopSelf() 方法或者其他组件调用 stopService() 方法时才停止。

        而IntentService很好的避免了这两个问题。

首先创建一个Service,让他继承IntentService类,然后在清单文件注册Service。

<service android:name=".MyIntentService"/>
  1. public class MyIntentService extends IntentService {
  2. }

然后在MainActivity.java 中启动MyIntentService

  1. Intent intent1 = new Intent(MainActivity.this, MyIntentService.class);
  2. startService(intent1);

最后编写MyIntentService代码,使他完成一个耗时操作。

  1. package com.example.servicedemo1;
  2. import android.app.IntentService;
  3. import android.content.Intent;
  4. import android.util.Log;
  5. import android.widget.Toast;
  6. import androidx.annotation.Nullable;
  7. /**
  8. * intentService服务完成一个耗时操作
  9. */
  10. public class MyIntentService extends IntentService {
  11. private static final String TAG = "MyIntentService";
  12. @Override
  13. public void onCreate() {
  14. super.onCreate();
  15. Log.i(TAG, "onCreate");
  16. }
  17. //构造方法
  18. public MyIntentService() {
  19. super("MyIntentService");
  20. }
  21. //耗时任务
  22. @Override
  23. protected void onHandleIntent(@Nullable Intent intent) {
  24. int i = 10;
  25. Log.e(TAG,"IntentService服务启动");
  26. Toast.makeText(this, "IntentService服务启动", Toast.LENGTH_SHORT).show();
  27. while (i > 0) {
  28. Log.i(TAG, i + "");
  29. i--;
  30. try {
  31. Thread.sleep(100);
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. Log.e(TAG,"IntentService服务结束");
  37. Toast.makeText(this, "IntentService服务结束", Toast.LENGTH_SHORT).show();
  38. }
  39. @Override
  40. public void onDestroy() {
  41. Log.i(TAG, "onDestroy");
  42. }
  43. }

效果如下:

        当启动IntentService时,会自动开启一个Thread,进行耗时操作,当Thread运行结束之后,IntentService也会结束。

  2、 IntentService服务为什么可以自动创建线程?为什么可以自动结束服务?

        通过源码了解一下他的处理方式。

IntentService是一个抽象类,继承Service类,所以它是一种特殊的Service,因为它内部封装了handlerThread和handler的。

public abstract class IntentService extends Service

 下面看onCreate()方法。

  1. private volatile Looper mServiceLooper;
  2. private volatile ServiceHandler mServiceHandler;
  3. private String mName;
  4. @Override
  5. public void onCreate() {
  6. super.onCreate();
  7. HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
  8. thread.start();
  9. mServiceLooper = thread.getLooper();
  10. mServiceHandler = new ServiceHandler(mServiceLooper);
  11. }

        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); 创建了一个Handler线程,thread.start() 启动了这个线程。

        thread.getLooper()  获取这个线程的Looper对象。

        new ServiceHandler(mServiceLooper) 创建一个内部类ServiceHandler对象,将Looper对象传递给它。

下一步走到了 onStartCommand() 方法

  1. @Override
  2. public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
  3. onStart(intent, startId);
  4. return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
  5. }

        这个方法里第一件事做的就是,调用onStart() 方法。

接下来看onStart() 方法

  1. @Override
  2. public void onStart(@Nullable Intent intent, int startId) {
  3. Message msg = mServiceHandler.obtainMessage();
  4. msg.arg1 = startId;
  5. msg.obj = intent;
  6. mServiceHandler.sendMessage(msg);
  7. }

         通过 mServiceHandler.sendMessage(msg) 将message发送到消息队列,消息处理又回到serviceHandler里面的handleMessage做。

紧接着回到内部类  ServiceHandler 中 执行 handleMessage() 方法。

  1. private final class ServiceHandler extends Handler {
  2. public ServiceHandler(Looper looper) {
  3. super(looper);
  4. }
  5. @Override
  6. public void handleMessage(Message msg) {
  7. onHandleIntent((Intent)msg.obj);
  8. stopSelf(msg.arg1);
  9. }
  10. }

        在这个方法中,调用了 onHandleIntent((Intent)msg.obj)  这个抽象方法,但它留给子类去实现。

  1. @WorkerThread
  2. protected abstract void onHandleIntent(@Nullable Intent intent);

        最后调用  stopSelf(msg.arg1)  停止服务,给出的定义是立即停止,但是当有参数的时候,会等所有的任务都执行完,才停止服务。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/679656
推荐阅读
相关标签
  

闽ICP备14008679号