当前位置: 首页 > news >正文

【Android】安卓四大组件之Service用法

文章目录

  • 使用Handler更新UI
  • Service
    • 基本特点
    • 启动方式
      • 非绑定式服务
        • 使用步骤
      • 绑定式服务
        • 步骤
    • 生命周期
      • 非绑定式
        • 启动阶段
        • 结束阶段
      • 绑定式
        • 启动阶段
        • 结束阶段
    • 前台Service
      • 使用步骤
      • 结束
        • 结束Service本身
        • 降级为普通Service
        • 降级为普通Service

使用Handler更新UI

  1. 主线程创建Handler对象,重写handlerMessage方法
  2. 子线程创建Message对象,使用Handler对象调用sendMessage方法发送消息,发到MessageQueue
  3. Looper一直尝试从MessageQueue中取出待处理消息,分发给Handler的handlerMessage方法中

image-20240806194619542

1722944819734

public class MainActivity extends AppCompatActivity {// 创建一个 Handler 实例,用于在主线程处理消息private Handler handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);// 当接收到的消息的 what 属性为 1 时执行以下代码if (msg.what == 1) {// 获取消息中的数据并转换为字符串String data = (String) msg.obj;// 将 TextView 的文本设置为接收到的数据tv.setText(data);}}};private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 设置活动的布局setContentView(R.layout.activity_main);// 获取布局文件中的 TextView 控件tv = findViewById(R.id.tv_response);// 获取布局文件中的 Button 控件Button button = findViewById(R.id.btn_send);// 为按钮设置点击事件监听器button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 创建一个新的 Message 对象Message message = new Message();// 设置消息的内容message.obj = "数据";// 设置消息的标识符message.what = 1;// 通过 handler 发送消息handler.sendMessage(message);}});}
}

Service

基本特点

  • 后台执行: Service 主要用于在后台执行一些长时间运行的操作,比如音乐播放、文件下载等,而不会影响用户界面的交互。
  • 没有界面: Service 不像 Activity 那样有界面。它运行在后台,通常没有用户界面。
  • 主线程: Service 运行在主线程中,因此在 Service 中执行耗时操作(如网络请求或文件操作)会阻塞主线程,可能会导致应用无响应。为了避免这种情况,通常需要使用异步机制,如 AsyncTaskHandlerExecutorService 等。

启动方式

非绑定式服务

(Started Service)

  • 启动方式:通过 startService() 方法启动。
  • 生命周期:服务的生命周期与启动它的组件无关。服务一旦启动,即使启动它的组件被销毁,服务仍会继续在后台运行,直到它自己被停止(通过 stopSelf()stopService())。
  • 交互:启动的服务不能被组件直接调用其方法。如果需要与服务进行交互,需要通过广播、MessengerAIDL 等方式。
  • 用途:适用于需要在后台执行长时间操作的情况,例如,下载文件、播放音乐等。
使用步骤
  1. 定义服务

定义一个继承自 Service 的类,并实现它的生命周期方法。

public class MyService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {super.onCreate();Log.d("MyService", "onCreate()");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d("MyService", "onStartCommand()");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d("MyService", "onDestroy()");}
}
  1. AndroidManifest.xml 中声明服务

确保在你的 AndroidManifest.xml 文件中注册服务:

<service android:name=".MyBoundService" />
  1. 启动服务
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void startService(View view) {Intent intent = new Intent(this, MyService.class);startService(intent);}
}
  1. 关闭服务

  2. 由启动者(通常是Activity)调用 stopService 方法。

  3. 服务内部调用 stopSelf 方法。

  • 由启动者关闭服务

在Activity中,可以通过调用 stopService 来停止服务:

Intent intent = new Intent(this, MyService.class);
stopService(intent);
  • 服务内部关闭自己

服务可以在内部调用 stopSelf 方法来停止自己:

public class MyService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 某些逻辑操作完成后,停止服务stopSelf();return START_NOT_STICKY;}
}

绑定式服务

(Bound Service)

  • 启动方式:通过 bindService() 方法启动。
  • 生命周期:服务的生命周期与绑定它的组件(如 Activity)有关。绑定服务的存在时间是基于组件的生命周期,如果所有绑定它的组件都被销毁,服务也会被销毁。
  • 交互:允许组件与服务进行交互,组件可以通过 ServiceConnection 接口获取到服务的引用,从而调用服务中的方法。
  • 用途:适用于需要与服务进行长期交互的情况,例如,组件需要获取服务的数据或调用服务中的方法。
步骤
  1. 定义服务

定义一个继承自 ServiceMyBindService类,并实现 onBind() 方法以返回一个实现IBinder 接口的类的对象。这个 IBinder 对象将用于与客户端进行通信。我们定义一个MyBinder类继承自Binder类,Binder类实现了IBinder接口

public class MyBindService extends Service {private static final String TAG = "MyBindService";// 测试服务的方法public void testService() {Log.d(TAG, "服务的测试");}@Overridepublic void onCreate() {Log.d(TAG, "onCreate executed");super.onCreate();// 在服务创建时初始化一些资源}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "onStartCommand executed");// 这里可以处理服务启动时的逻辑return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {Log.d(TAG, "onDestroy executed");super.onDestroy();// 在服务销毁时释放资源}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG, "onBind executed");return new MyBinder(this);}@Overridepublic boolean onUnbind(Intent intent) {Log.d(TAG, "onUnbind executed");return super.onUnbind(intent);// 可以在这里处理服务解绑时的逻辑}// Binder类实现了IBinder接口public class MyBinder extends Binder {private final MyBindService mMyBindService;// 构造函数,用于初始化服务实例public MyBinder(MyBindService myBindService) {mMyBindService = myBindService;}// 提供一个方法来获取服务实例public MyBindService getService() {return mMyBindService;}// 测试Binder的方法public void test() {Log.d(TAG, "MyBinder测试");mMyBindService.testService();}}
}
  1. AndroidManifest.xml 中声明服务
<service android:name=".MyBoundService" />
  1. 绑定服务

在你的组件(如 Activity)中,通过 bindService() 方法绑定到服务。你需要实现 ServiceConnection 接口来处理与服务的连接状态。

public class MainActivity extends AppCompatActivity {// 定义一个MyBinder对象,用于绑定服务后与服务交互public MyBindService.MyBinder myBinder = null;// 定义一个ServiceConnection对象,用于管理服务的连接和断开private ServiceConnection coon = new ServiceConnection() {// 当服务成功连接时回调该方法@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 将传入的IBinder对象转换为MyBindermyBinder = (MyBindService.MyBinder) service;// 调用MyBinder的test方法,测试服务功能myBinder.test();}// 当服务断开连接时回调该方法@Overridepublic void onServiceDisconnected(ComponentName name) {// 可以在这里处理服务断开时的逻辑}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}// 绑定服务的方法public void bindService(View view) {Intent intent = new Intent(this, MyBindService.class);bindService(intent, coon, BIND_AUTO_CREATE);}
}
  1. 解除绑定

通过 unbindService() 方法来完成解除绑定的操作

@Override
protected void onStop() {super.onStop();if (isBound) {unbindService(connection);isBound = false;}
}

服务的绑定和解除绑定的注意事项

  • 绑定后:一旦绑定成功,组件可以通过服务提供的方法进行交互。
  • 解除绑定后:如果没有其他组件绑定该服务,服务会被销毁(如果服务是绑定服务),并调用 onDestroy() 方法进行清理。
  • 线程处理:如果服务需要执行长时间运行的任务,最好在服务中使用后台线程或异步任务来避免阻塞主线程。

生命周期

Service 的生命周期主要包括以下几个阶段:

  • onCreate(): 当服务第一次被创建时调用。通常在这里进行服务初始化。
  • onStartCommand(Intent intent, int flags, int startId): 当服务被 startService() 方法启动时调用。在这个方法中可以处理服务的任务。返回的 int 值决定了服务被系统杀掉后如何重启。
  • onBind(Intent intent): 当 bindService() 方法被调用时触发。用于提供与 Service 的绑定接口。若 Service 不需要绑定,可以返回 null
  • onDestroy(): 当服务被销毁时调用。通常在这里进行清理工作。

非绑定式

启动阶段
  • onCreate()
    • 只会在服务首次创建时调用一次。适合在这里做一些一次性的初始化工作。
  • onStartCommand(Intent intent, int flags, int startId)
    • 每次调用 startService 时都会执行。可以在这里处理传入的 Intent。
结束阶段

启动者(Activity)调用 stopService 或服务内部调用 stopSelf

  • 当 Activity 调用 stopService(Intent intent) 或服务内部调用 stopSelf() 方法时,服务会停止并触发 onDestroy 方法。

  • onDestroy()

    • 服务销毁前的最后一个方法。适合在这里做一些资源释放的收尾工作。

      @Override
      public void onDestroy() {super.onDestroy();// 释放资源
      }
      

绑定式

启动阶段

**启动者(Activity)**调用 bindService(Intent intent, ServiceConnection conn, int flags)

  • onCreate()
    • 只会在服务首次创建时调用一次。适合在这里做一些一次性的初始化工作。
  • onBind(Intent intent)
    • 只会在首次绑定时执行一次。返回一个 IBinder 对象,供客户端与服务进行通信。
结束阶段

启动者(Activity)销毁或调用 unbindService 方法

  • 当 Activity 销毁或调用 unbindService(ServiceConnection conn) 方法时,会解除与服务的绑定。当没有绑定者时,服务会销毁。

  • onUnbind(Intent intent)

    • 解除绑定:当所有客户端都解除绑定时,会调用此方法。可以在这里处理一些解绑相关的逻辑。
  • onDestroy()

    • 销毁:服务销毁前的最后一个方法。适合在这里做一些资源释放的收尾工作。

注意事项

  • 服务绑定和解除绑定:确保在 Activity 的生命周期中正确绑定和解除绑定服务,以避免内存泄漏。
  • 资源释放:在 onDestroy 中释放所有资源,确保服务完全终止时不留下任何资源占用。

onCreate->onBind->onUnbind->onDestory

前台Service

前台服务 (Foreground Service) 是一种能够持续运行并与用户进行交互的服务。相比于后台服务,前台服务具有更高的优先级,通常不会被系统回收。

使用步骤

  1. 创建通知 (Notification)

前台服务必须显示一个通知来告知用户该服务正在运行。可以使用 NotificationCompat.Builder 来创建通知。

Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("服务正在运行").setContentText("前台服务示例").setSmallIcon(R.drawable.ic_service_icon).build();
  1. 调用startForeground方法

在服务的 onCreateonStartCommand 方法中调用 startForeground(notificationId, notification) 方法,将服务提升到前台状态。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("服务正在运行").setContentText("前台服务示例").setSmallIcon(R.drawable.ic_service_icon).build();startForeground(1, notification);// 其他业务逻辑return START_STICKY;
}
  1. 申请权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

结束

  • 完全停止ServicestopServicestopSelf
  • 降级Service状态stopForeground(true) 将Service从前台状态退出并移除通知,但Service仍然在运行,只是优先级降低。
结束Service本身
  • 正常的结束Service方式:外部调用 stopService 方法或自身调用 stopSelf 方法。这两种方式都会完全停止Service。当Service结束后,所有与之相关的通知也会被移除。

示例:

// 通过外部调用
stopService(new Intent(context, MyService.class));// 通过Service自身调用
stopSelf();
降级为普通Service

退出Service的前台状态,降级为普通Service

  • 调用 stopForeground(true) 方法:这会将Service从前台状态退出,变成普通的后台Service。这样做会降低Service的优先级,在系统内存不足时可能会被回收销毁。参数 true 表示同时移除通知。

示例:

// 将Service退出前台状态,同时移除通知
stopForeground(true);

elf` 方法。这两种方式都会完全停止Service。当Service结束后,所有与之相关的通知也会被移除。

示例:

// 通过外部调用
stopService(new Intent(context, MyService.class));// 通过Service自身调用
stopSelf();
降级为普通Service

退出Service的前台状态,降级为普通Service

  • 调用 stopForeground(true) 方法:这会将Service从前台状态退出,变成普通的后台Service。这样做会降低Service的优先级,在系统内存不足时可能会被回收销毁。参数 true 表示同时移除通知。

示例:

// 将Service退出前台状态,同时移除通知
stopForeground(true);


感谢您的阅读
如有错误烦请指正


相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • QT生成.exe文件无法在未安装QT的电脑上运行的解决办法
  • CP AUTOSAR标准之DefaultErrorTracer(AUTOSAR_SWS_DefaultErrorTracer)(更新中……)
  • 视频监控汇聚平台LntonCVS视频监控管理平台解决方案和常见的接入方式
  • 黑神画Ⅱ--Unix 是下一代人工智能的模板吗?
  • ios 5.5寸、ipad13英寸如何截屏
  • 网络安全-渗透测试工具及插件介绍和使用方法
  • RabbitMQ:发送者的可靠性之配置发送者重试机制
  • 在 Linux 系统中下载 Python 并配置环境
  • 使用GPT-4o mini融合GraphRAG技术进行实战应用
  • 鸿蒙媒体开发【拼图】拍照和图片
  • Flask数据库操作(第四阶段)
  • CLM安装及运行、移植、编译、结果处理、可视化;CESM移植、安装及快速运行
  • 【JavaEE】定时器
  • MySQL基础操作指南:从连接到数据管理的完整指南
  • Excel表列名称
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Android系统模拟器绘制实现概述
  • JavaScript 基础知识 - 入门篇(一)
  • JavaScript异步流程控制的前世今生
  • Java读取Properties文件的六种方法
  • Just for fun——迅速写完快速排序
  • LeetCode29.两数相除 JavaScript
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • Redis 中的布隆过滤器
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • uni-app项目数字滚动
  • Web标准制定过程
  • Windows Containers 大冒险: 容器网络
  • 动态规划入门(以爬楼梯为例)
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 区块链技术特点之去中心化特性
  • 设计模式走一遍---观察者模式
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 网络应用优化——时延与带宽
  • 一个完整Java Web项目背后的密码
  • 正则与JS中的正则
  • Android开发者必备:推荐一款助力开发的开源APP
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • 仓管云——企业云erp功能有哪些?
  • ​ArcGIS Pro 如何批量删除字段
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​什么是bug?bug的源头在哪里?
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #565. 查找之大编号
  • #70结构体案例1(导师,学生,成绩)
  • #DBA杂记1
  • (03)光刻——半导体电路的绘制
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (Python) SOAP Web Service (HTTP POST)
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (二)延时任务篇——通过redis的key监听,实现延迟任务实战
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (附源码)springboot猪场管理系统 毕业设计 160901