Android Service的解析

人不走空

                                                                      

      🌈个人主页:人不走空      

💖系列专栏:算法专题

⏰诗词歌赋:斯是陋室,惟吾德馨

 

Android服务,即Service,是Android四大组件之一,是一种程序后台运行的方案,用于不需要用户交互,长期运行的任务场景。

Service并不是在单独进程中运行,也是运行在应用程序进程的主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的服务也会停止运行。

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

  1. 执行需要长时间运行的操作,这个操作不与用户进行交互,如网络下载、大文件I/O、复杂计算。

  2. 应用内或应用间数据通信,Android每个应用程序都在自己的dalvik虚拟机中运行,一个应用是不允许访问其他应用的内存信息的,为此Android引入了Content Provider在不同应用间共享数据,BroadcastReceiver广播信息给不同应用程序,但Content Provider更多用于数据的共享,BroadcastReceiver广播的信息会被所有应用接收较耗费系统资源,对于两个应用间动态的进行交互还需要通过Service来完成。

Service的使用

Service的创建和Activity类似,也是通过Intent来实现的,既然是安卓四大组件之一,那么它也需要在清单文件中进行注册的。具体步骤如下。

Service的创建

新建一个TgsService继承自Service,并重写父类的onCreate()、onStartCommand()和onDestroy()方法,如下面的代码所示:

public class TgsService extends Service {
    public static final String TAG = "TgsService";
    @Override    public void onCreate() {        super.onCreate();        Log.d(TAG, "onCreate");    }
    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d(TAG, "onStartCommand");        return super.onStartCommand(intent, flags, startId);    }
    @Override    public void onDestroy() {        super.onDestroy();        Log.d(TAG, "onDestroy");    }
    @Override    public IBinder onBind(Intent intent) {        return null;    }}

Service的注册

在清单文件中注册它,如下所示:

<service android:name="com.tgs.demo.TgsService"            android:enabled="true"            android:exported="true"/>
  • enabled属性:是指该服务是否能够被实例化。如果设置为true,则能够被实例化,否则不能被实例化。默认值是true,一般情况下,我们都会需要实例化,所以也可以选择不设置。

  • exported属性:用于指示该服务是否能够被其他应用程序组件调用或跟它交互。如果设置为true,则能够被调用或交互(通常如果一个服务需要跨进程使用需要这么设置),设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。

Service的启动

接下来创建一个TgsActivity的测试活动,用于在其中创建TgsService对象,并在点击按钮时启动服务,示例代码如下:

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button startBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        startBtn = (Button) findViewById(R.id.btn_start_service);
        startBtn.setOnClickListener(this);    }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_start_service:                    Intent startIntent = new Intent(this, TgsService.class);                    startService(startIntent);                    break;            }        }    }}

Service和Thread

如第一节所介绍的,Service是一个运行于后台的服务,一些比较耗时的操作也可以放在这里运行。而Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。这就会让人对这两个概念产生混淆了。

Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread?答案是:Service和Thread之间没有任何关系!前面有提到,Service其实是运行在主线程里的,因此它和Thread并没有关系。

Service与Thread的区别如下:

  1. Service是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的main线程上的。如果是Remote Service,那么对应的Service则是运行在独立进程的main线程上。

  2. Thread是程序执行的最小单元,可以用Thread来执行一些异步的操作。

  3. 在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需要长时间运行的情况下使用线程。

  4. 如果任务占用CPU时间多,资源大的情况下,要使用线程。

那么如果用户既想使用Service的优点,又想使用Thread的优点,要怎么实现?关于这一点,Google已经帮我们想到了。即下节要介绍的IntentService。

IntentService

IntentService的概念

IntentService是Android中的一个系统封装类,继承自四大组件之一的Service,主要用于处理异步请求,实现多线程,它有以下特点:

  1. 是一种特殊的Service,继承自Service并且本身就是一个抽象类。

  2. 用于在后台执行耗时的异步任务,当任务完成后会自动停止。

  3. 有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务。

  4. 内部通过HandlerThread和Handler实现异步操作。

  5. 创建IntentService时,只需实现onHandleIntent和构造方法,onHandleIntent为异步方法,可以执行耗时操作。

IntentService的创建

编写自己的Service类继承IntentService,并重写其中的onHandleIntent(Intent)方法,该方法是IntentService的一个抽象方法,用来处理我们通过startService方法开启的服务,传入参数Intent就是开启服务的Intent,如下所示:

public class TgsIntentService extends IntentService {
    private static final String TAG = TgsIntentService.class.getSimpleName();
    public TgsService() {        super(TAG);    }
    @Override    protected void onHandleIntent(Intent intent) {        // 在这里添加我们要执行的异步代码    }}

IntentService的注册

接下来在AndroidManifest文件中的Application标签下添加刚刚创建的服务,如下所示:

<service android:name="com.tgs.demo.TgsIntentService" />

IntentService的启动

然后创建一个TgsActivity的测试活动,并在点击按钮时调用startService系统函数来开启IntentService的服务,示例代码如下:

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button startIntentServiceBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        startIntentServiceBtn = (Button) findViewById(R.id.btn_start_intent_service);
        startIntentServiceBtn.setOnClickListener(this);    }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_start_intent_service:                    Intent intent = new Intent(TgsActivity.this, TgsIntentService.class);                    startService(intent);                    break;            }        }    }}

Service的终止

一个已经启动了的Service必须管理它自己的生命期,系统不会停止或销毁这种Service,除非内存不够用了。Service在onStartCommand()返回后会继续运行。所以,service必须调用stopSelf()停止自己或由另一个组件调用stopService()来停止它。

一旦通过stopSelf()或stopService()发出了停止请求,系统就会尽可能快地销毁service。

关于Service的终止,需要注意以下几点:

  1. startService要stopSelf或者stopService才能终结。

  2. bindService要组件全部解绑后才会终结。

  3. 低内存的时候系统会主动停止和回收后台Service。

  4. 前台service很少被系统杀死,后台service随着时间推移变得更加可能被系统杀死。

  5. service被杀后会重启,但是取决于onStartCommand的返回值。

接下来创建一个TgsActivity的测试活动,用于在其中创建TgsService对象,并在点击按钮时停止服务,示例代码如下:​​​​​​​

public class TgsActivity extends Activity implements View.OnClickListener {
    private Button stopBtn;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_start);
        stopBtn = (Button) findViewById(R.id.btn_stop_service);
        stopBtn.setOnClickListener(this);      }
    @Override    public void onClick(View v) {        if (v != null) {            switch (v.getId()) {                case R.id.btn_stop_service:                    Intent stopIntent = new Intent(this, TgsService.class);                    stopService(stopIntent);                    break;                      }        }    }}

参考链接

  • https://developer.android.com/reference/android/app/Service

  • https://developer.android.com/reference/android/app/Service#WhatIsAService

  • https://developer.android.com/reference/android/app/Service#ServiceLifecycle

  • https://developer.android.com/reference/android/app/Service#Permissions

  • https://developer.android.com/reference/android/app/Service#ProcessLifecycle

  • https://developer.android.com/reference/android/app/Service#LocalServiceSample

  • https://developer.android.com/reference/android/app/Service#RemoteMessengerServiceSample

客户端27

Android开发12

客户端 · 目录

上一篇Android多线程的种类及使用方法下一篇Android组件之ContentProvider


作者其他作品:

【Java】Spring循环依赖:原因与解决方法

OpenAI Sora来了,视频生成领域的GPT-4时代来了

[Java·算法·简单] LeetCode 14. 最长公共前缀 详细解读

【Java】深入理解Java中的static关键字

[Java·算法·简单] LeetCode 28. 找出字a符串中第一个匹配项的下标 详细解读

了解 Java 中的 AtomicInteger 类

算法题 — 整数转二进制,查找其中1的数量

深入理解MySQL事务特性:保证数据完整性与一致性

Java企业应用软件系统架构演变史​​​​​​​ 

  • 19
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人不走空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值