Service是一种可以长期在后台运行而不提供界面的应用组件。服务又可以分为前台服务和后台服务
- 前台服务前台服务是指是能让用户感知到服务正在运行,因此服务必须显示通知。比如QQ音乐的播放,如果打开了播放控制里的状态栏显示,当你播放音乐时,状态栏里会显示你正在播放的音乐,再比如下载软件,也同样会在状态栏里显示下载进度
- 后台服务后台服务与前台服务相反,用户通常感知不到后台服务正在运行
前台服务的优先级很高,因此出现系统内存不足时系统也不会将前台服务回收,而后台服务在系统内存不足时有可能会被系统回收
Service启动方式
-
startService,Intent指明了启动的Service所在类为StartService。通过该方式启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行显式启动通过类名称来启动,需要在Intent中指明Service所在的类,并调用startService (lntent)启动service。显式启动停止Service,需要将启动Service的Intent传递给stopService (Intent)函数。使用unbindService()方法取消绑定
//启动服务 startService(new Intent(this, MyService.class)); //停止服务 stopService(new Intent(this, MyService.class));
-
bindService
使用bindService()方法启动Service,当调用者通过bindService()函数绑定Service时,onCreate()函数和onBinde ( )函数将被先后调用。通过该方式启动Service,访问者与Service绑定在一起,访问者一旦退出了,Service也就终止了。
绑定模式使用bindService()方法启动Service//绑定服务 bindService(Intent service,ServiceConnection conn,int flags); //解绑服务 unbindService(ServiceConnection conn)
- service:该参数通过Intent指定需要启动的service
- conn:该参数是ServiceConnnection对象,当绑定成功后,系统将调用serviceConnnection的onServiceConnected ()方法,当绑定意外断开后,系统将调用ServiceConnnection中的onServiceDisconnected方法
- flags:该参数指定绑定时是否自动创建Service。如果指定为BIND_AUTO_CREATE,则自动创建,指定为0,则不自动创建
unbindService()方法成功后,系统并不会调用onServiceConnected(),因为onServiceConnected()仅在意外断开绑定时才被调用。当调用者通过unbindService()函数取消绑定Service时,onUnbind()函数将被调用。如果onUnbind()函数返回true,则表示重新绑定服务时,onRebind ()函数将被调用。
-
启动实例
-
Activity代码
package com.xiaozhi.myservice; import androidx.appcompat.app.AppCompatActivity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; public class MainActivity extends AppCompatActivity { boolean flag = true; private static final String TAG = "xiaozhi"; private MyService.MyBinder mBinder; @Override protected void onCreate(Bundle savedInstanceState) { Log.e(TAG, "MainActivity-----" + Thread.currentThread().getName() + "--" + Thread.currentThread().getId()); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } //启动服务 public void startService(View view) { startService(new Intent(this, MyService.class)); } //停止服务 public void stopService(View view) { stopService(new Intent(this, MyService.class)); } //MainActivity与MyService的桥梁 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG, name.toString()); mBinder = (MyService.MyBinder) service; mBinder.doTask(); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, name.toString()); } }; //绑定服务 public void bindService(View view) { bindService(new Intent(this, MyService.class), connection, Context.BIND_AUTO_CREATE); } //解绑服务 public void unbindService(View view) { if (flag) { unbindService(connection); flag = false; } } //解绑服务的常规写法,在Activity被摧毁时执行 @Override public void onDestroy() { super.onDestroy(); if (flag) { unbindService(connection); flag = false; } } }
-
Service代码
package com.xiaozhi.myservice; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MyService extends Service { private static final String TAG = "xiaozhi"; private MyBinder mBinder; @Override public void onCreate() { super.onCreate(); Log.e(TAG, "onCreate"); Log.e(TAG, "MyService-----" + Thread.currentThread().getName() + "--" + Thread.currentThread().getId()); mBinder = new MyBinder(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e(TAG, "onStartCommand"); new Thread(new Runnable() { @Override public void run() { // 任务逻辑 Log.e(TAG, "onStartCommand开启子线程执行耗时操作"); } }).start(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG, "onDestroy"); } //onBind()是Service必须实现的方法,返回的IBinder对象相当于Service组件的代理对象,Service允许其他程序组件通过IBinder对象来访问Service内部数据,这样即可实现其他程序组件与Service之间的通信。 @Override public IBinder onBind(Intent intent) { if (mBinder != null) { Log.e(TAG, "onBind"); return mBinder; } return null; } @Override public boolean onUnbind(Intent intent) { Log.e(TAG, "onUnbind"); return super.onUnbind(intent); } class MyBinder extends Binder { public void doTask() { Log.e(TAG, "doTask"); new Thread(new Runnable() { @Override public void run() { // 任务逻辑 Log.e(TAG, "doTask开启子线程执行耗时操作"); } }).start(); } } }
-
布局代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startService" android:onClick="startService" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="stopService" android:onClick="stopService" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="bindService" android:onClick="bindService" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="unbindService" android:onClick="unbindService" /> </LinearLayout>
-
在AndroidManifest.xml文件中声明一个Service组件
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".MyService" /> </application>
-
-
其他启动方式
- 使用startService()启动服务之后,再使用bindService()绑定上该服务,此时调用stopSelf()或stopService()并不能结束服务,还需要调用unbindService(),服务才会真的被关闭
- 可以使用startForegroundService()开启前台服务,startForegroundService()与startService()相似,只不过使用startForegroundService()后,5s内必须调用startForeground(),否则会在logcat中报错。如果android设备9.0及以上,需要在AndroidMAnifest.xml中添加FOREGROUND_SERVICE权限
Service生命周期
- startService启动的生命周期
- onCreate()当Service第一次被创建时,由系统调用
- onStartCommand() 当startService方法启动Service时,该方法被调用
- onDestroy() 当Service不再使用时,由系统调用
- 一个startService只会创建一次,销毁一次,但可以开始多次,因此,onCreate()和onDestroy()方法只会被调用一次,而onStart()方法会被调用多次
- bindService启动的生命周期
- onCreate() 当Service被创建时,由系统调用
- onBind() 当bindService方法启动Service时,该方法被调用
- onUnbind() 当unbindService方法解除绑定时,该方法被调用
- onDestroy() 当Service不再使用时,由系统调用
- 一个bindService可以创建多次,销毁多次,重复使用
Service和Thread的区别
- Service是安卓中系统的组件,它运行在独立进程的主线程中,不可以执行耗时操作
- Thread是程序执行的最小单元,分配CPU的基本单位,可以开启子线程执行耗时操作
- Service在不同Activity中可以获取自身实例,可以方便的对Service进行操作
- Thread在不同的Activity中难以获取自身实例,如果Activity被销毁,Thread实例就很难再获取得到
IntentService
-
IntentService是 Scrvice 的子类,因此它不是普通的Service,它比普通的Service增加了额外的功能。先看Service本身存在的两个问题
- Service不会专门启动一个单独的进程,Service与它所在应用位于同一个进程中
- Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务
-
IntentService正好弥补了Service的不足。IntentService的特点:
- IntentService会创建单独的worker线程来处理所有的Intent请求
- IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无须处理多线程问题
-
IntentService实例
package com.xiaozhi.myservice; import android.app.IntentService; import android.content.Intent; import android.util.Log; import androidx.annotation.Nullable; public class MyIntentService extends IntentService { private static final String TAG = "MyIntentService"; public MyIntentService() { super("MyIntentService"); } @Override protected void onHandleIntent(Intent intent) { Log.e(getClass().getName(), "onHandleWork"); for (int i = 0; i < 3; i++) { try { Log.e(getClass().getName(), "Number:开始"+i); Thread.sleep(10000); Log.e(getClass().getName(), "Number:结束"+i); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void onDestroy() { super.onDestroy(); Log.e(getClass().getName(), "onDestroy"); } }
启动
startService(new Intent(this, MyIntentService.class));
log打印
11:10:13.217 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: onHandleWork 11:10:13.217 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始0 11:10:23.218 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束0 11:10:23.219 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始1 11:10:33.221 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束1 11:10:33.221 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始2 11:10:43.223 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束2 11:10:43.229 4591-4591/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: onDestroy
-
总结
-
IntentService 是继承于 Service 并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个
-
普通Service直接执行20S的的耗时操作,会阻塞主线程,造成ANR(程序无响应)异常,而IntentService执行30S的耗时操作,不会阻塞主线程,更不会产生ANR
-
执行完onHandleIntent()方法里面的耗时操作后,会自行调用onDestroy()方法,进行关闭
-
IntentService本质是采用Handler & HandlerThread方式:
-
通过HandlerThread单独开启一个名为IntentService的线程
-
创建一个名叫ServiceHandler的内部Handler
-
把内部Handler与HandlerThread所对应的子线程进行绑定
-
通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()
-
通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务
-
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了