🌈个人主页:人不走空
💖系列专栏:算法专题
⏰诗词歌赋:斯是陋室,惟吾德馨
Android服务,即Service,是Android四大组件之一,是一种程序后台运行的方案,用于不需要用户交互,长期运行的任务场景。
Service并不是在单独进程中运行,也是运行在应用程序进程的主线程中,在执行具体耗时任务过程中要手动开启子线程,应用程序进程被杀死,所有依赖该进程的服务也会停止运行。
由于ANR对Activity和BroadcastReceiver响应时间的限制(Activity对事件响应不超过5秒,BroadcastReceiver执行不超过10秒),使得在其中都不适合执行较耗时操作,这样像网络、数据库、复杂计算这类耗时操作的执行就需要一个组件来承担。Service作为Android四大组件之一,其功能之一就是耗时操作的执行,主要功能如下:
-
执行需要长时间运行的操作,这个操作不与用户进行交互,如网络下载、大文件I/O、复杂计算。
-
应用内或应用间数据通信,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的区别如下:
-
Service是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主进程的main线程上的。如果是Remote Service,那么对应的Service则是运行在独立进程的main线程上。
-
Thread是程序执行的最小单元,可以用Thread来执行一些异步的操作。
-
在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务。同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需要长时间运行的情况下使用线程。
-
如果任务占用CPU时间多,资源大的情况下,要使用线程。
那么如果用户既想使用Service的优点,又想使用Thread的优点,要怎么实现?关于这一点,Google已经帮我们想到了。即下节要介绍的IntentService。
IntentService
IntentService的概念
IntentService是Android中的一个系统封装类,继承自四大组件之一的Service,主要用于处理异步请求,实现多线程,它有以下特点:
-
是一种特殊的Service,继承自Service并且本身就是一个抽象类。
-
用于在后台执行耗时的异步任务,当任务完成后会自动停止。
-
有较高的优先级,不易被系统杀死(继承自Service的缘故),因此比较适合执行一些高优先级的异步任务。
-
内部通过HandlerThread和Handler实现异步操作。
-
创建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的终止,需要注意以下几点:
-
startService要stopSelf或者stopService才能终结。
-
bindService要组件全部解绑后才会终结。
-
低内存的时候系统会主动停止和回收后台Service。
-
前台service很少被系统杀死,后台service随着时间推移变得更加可能被系统杀死。
-
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企业应用软件系统架构演变史