深入分析 Android Service (五)

文章目录

    • 深入分析 Android Service (五)
    • 1. 深入分析 Service 与 Activity 之间的通信
    • 2. Messenger 的内部工作原理
      • 2.1 服务端实现
      • 2.2 客户端实现
    • 3. AIDL 的内部工作原理
      • 3.1 定义 AIDL 接口
      • 3.2 服务端实现
      • 3.3 客户端实现
    • 4. Service 的优化建议和最佳实践
      • 4.1 异步操作
      • 4.2 资源管理
      • 4.3 前台服务
      • 4.4 权限管理
    • 5. 使用场景和总结

深入分析 Android Service (五)

1. 深入分析 Service 与 Activity 之间的通信

前面我们介绍了通过 MessengerAIDL 实现 ServiceActivity 之间的通信。接下来,我们将进一步深入分析这些通信机制的内部工作原理和设计思想。

2. Messenger 的内部工作原理

Messenger 是基于 Handler 实现的轻量级进程间通信(IPC)机制。它利用 Binder 传递消息。下面是 Messenger 工作的详细流程:

  1. 创建 Messenger 和 Handler

    • 服务端创建一个 Handler,用于处理客户端发送的消息。
    • 使用这个 Handler 创建一个 Messenger 对象,并通过 Binder 返回给客户端。
  2. 绑定服务

    • 客户端通过 bindService 方法绑定服务,获取服务端的 Messenger 对象。
  3. 发送消息

    • 客户端通过 Messenger.send(Message msg) 方法发送消息到服务端。
    • 消息通过 Binder 通道传递到服务端的 Handler 进行处理。

以下是服务端和客户端实现的具体代码示例:

2.1 服务端实现

public class MessengerService extends Service {
    static final int MSG_SAY_HELLO = 1;

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(getApplicationContext(), "Hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    final Messenger messenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

2.2 客户端实现

public class MainActivity extends AppCompatActivity {
    Messenger messenger = null;
    boolean isBound = false;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            messenger = new Messenger(service);
            isBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            messenger = null;
            isBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MessengerService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        Button sendButton = findViewById(R.id.sendButton);
        sendButton.setOnClickListener(v -> {
            if (isBound) {
                Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
                try {
                    messenger.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

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

3. AIDL 的内部工作原理

AIDL(Android Interface Definition Language)是一种定义接口的语言,用于进程间通信(IPC)。它允许在不同进程间传递复杂的数据结构。AIDL 的内部工作原理如下:

  1. 定义 AIDL 接口

    • 开发者使用 .aidl 文件定义接口和方法。
  2. 编译生成代码

    • 编译器生成用于 IPC 的 StubProxy 类。
  3. 实现 AIDL 接口

    • 服务端实现 Stub 类,处理客户端请求。
  4. 绑定服务

    • 客户端通过 bindService 方法绑定服务,获取 StubProxy 对象。
  5. 调用远程方法

    • 客户端通过 Proxy 对象调用远程方法,方法调用通过 Binder 通道传递到服务端的 Stub 类进行处理。

以下是详细的实现代码示例:

3.1 定义 AIDL 接口

package com.example;

interface IMyAidlInterface {
    int add(int a, int b);
}

3.2 服务端实现

public class MyAidlService extends Service {
    private final IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
        @Override
        public int add(int a, int b) {
            return a + b;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

3.3 客户端实现

public class MainActivity extends AppCompatActivity {
    IMyAidlInterface myAidlService = null;
    boolean isBound = false;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAidlService = IMyAidlInterface.Stub.asInterface(service);
            isBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myAidlService = null;
            isBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, MyAidlService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

        Button addButton = findViewById(R.id.addButton);
        addButton.setOnClickListener(v -> {
            if (isBound) {
                try {
                    int result = myAidlService.add(5, 3);
                    Toast.makeText(MainActivity.this, "Result: " + result, Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

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

4. Service 的优化建议和最佳实践

4.1 异步操作

为了避免阻塞主线程,在 Service 中处理耗时操作时,应使用异步任务或线程池。例如,使用 AsyncTaskExecutorService 来处理后台任务。

4.2 资源管理

确保在 Service 停止时释放所有资源,避免内存泄漏。例如,在 onDestroy 方法中关闭任何打开的资源(如文件、网络连接等)。

4.3 前台服务

对于需要长期运行的服务,使用前台服务,并提供持续显示的通知,确保服务在系统资源紧张时不被杀死。

@Override
public void onCreate() {
    super.onCreate();
    executorService = Executors.newSingleThreadExecutor();

    // Create the notification channel for Android O and above
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel("download_channel", "Download Service", NotificationManager.IMPORTANCE_DEFAULT);
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (manager != null) {
            manager.createNotificationChannel(channel);
        }
    }

    // Start foreground service
    Notification notification = new NotificationCompat.Builder(this, "download_channel")
            .setContentTitle("Downloading")
            .setContentText("Downloading in progress")
            .setSmallIcon(R.drawable.ic_download)
            .build();
    startForeground(1, notification);
}

4.4 权限管理

在需要与其他应用通信的 Service 中,确保使用适当的权限保护机制,防止未授权访问。例如,使用 android:permission 属性限制哪些应用可以绑定服务。

<service android:name=".MyAidlService"
    android:permission="com.example.myapp.permission.BIND_MY_SERVICE">
    <intent-filter>
        <action android:name="com.example.myapp.BIND" />
    </intent-filter>
</service>

5. 使用场景和总结

Service 在 Android 应用中的使用场景广泛,包括但不限于:

  • 后台音乐播放:使用 Service 处理音乐播放任务,即使用户离开了应用界面,音乐也可以继续播放。
  • 数据同步:使用 Service 定期同步数据,如邮件、联系人、日历等。
  • 位置跟踪:使用 Service 持续获取并处理位置信息,实现位置跟踪功能。
  • 文件下载:使用 Service 在后台下载大文件,并在下载完成后通知用户。
  • 网络请求:使用 Service 处理长时间运行的网络请求,避免阻塞主线程。

通过深入理解和合理设计 Service,可以有效地提升 Android 应用的性能和用户体验。无论是简单的异步任务,还是复杂的跨进程通信,通过合理使用 Service,结合具体需求进行优化,是构建高效、稳定的 Android 应用的重要一环。希望以上示例和详细说明能够帮助开发者更好地理解和使用 Service,实现更强大和高效的应用功能。

欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/667271.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32的轻量级Web服务器设计

文章目录 一、前言1.1 开发背景1.2 实现的功能1.3 硬件模块组成1.4 ENC28J60网卡介绍1.5 UIP协议栈【1】目标与特点【2】核心组件【3】应用与优势 1.6 添加UIP协议栈实现创建WEB服务器步骤1.7 ENC28J60添加UIP协议栈实现创建WEB客户端1.8 ENC28J60移植UIP协议并编写服务器测试示…

关于亚马逊、速卖通、虾皮、Lazada等平台自养号测评IP的重要性

在自养号测评中&#xff0c;IP的纯净度是一个至关重要的问题&#xff0c;它直接关系到账号的安全性和稳定性如果使用了被平台识别为异常或存在风险的IP地址&#xff0c;那么账号可能会面临被封禁的风险。这将对账号的正常使用和测评过程中造成严重影响。而使用纯净的IP地址&…

用万界星空科技低代码平台能快速搭建一个云MES系统

一、低代码平台与MES:智能制造的新篇章 随着工业4.0和智能制造的兴起&#xff0c;企业对于生产过程的数字化、智能化需求日益迫切。传统的MES系统实施周期长、成本高&#xff0c;成为许多企业数字化转型的瓶颈。而低代码开发平台的出现为这一问题提供了新的解决思路。 二、万界…

数据库(12)——DQL聚合查询

常见的聚合函数 将一列数据作为一个整体&#xff0c;进行纵向计算。 函数功能count统计数量max最大值min最小值avg平均值sum求和 语法 SELECT 聚合函数 &#xff08;字段列表&#xff09;FROM 表名; 示例 这是我们的原始表&#xff1a; 求人物总数 select count(id) from in…

HTML静态网页成品作业(HTML+CSS)—— 冶金工程专业展望与介绍介绍网页(2个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有2个页面。 二、作品演示 三、代…

容器技术基础理论与常用命令:必知必会,效率翻倍!

如何利用容器技术提升你的工作效率&#xff1f;掌握基础理论和常用命令是必不可少的&#xff0c;本文将为你全面介绍容器技术&#xff0c;并教你必知必会的技能&#xff0c;让你工作、学习效率翻倍&#xff0c;对于网络安全工作者也是必不可少的技能&#xff01; 0. 引言 学习…

【WEEK14】 【DAY3】Swagger第一部分【中文版】

2024.5.29 Wednesday 目录 16.Swagger16.1.Swagger简介16.1.1.前后端分离16.1.2.前后端分离时代16.1.3.产生的问题16.1.4.解决方案16.1.5.Swagger 16.2.SpringBoot集成Swagger16.2.1.新建swagger-demo项目16.2.2.导入依赖16.2.2.1.springfox-swagger216.2.2.2.springfox-swagge…

linux部署运维1——centos7.9离线安装部署涛思taos2.6时序数据库TDengine

在实际项目开发过程中&#xff0c;并非一直都使用关系型数据库&#xff0c;对于工业互联网类型的项目来说&#xff0c;时序型数据库也是很重要的一种&#xff0c;因此掌握时序数据库的安装配置也是必要的技能&#xff0c;不过对于有关系型数据库使用的开发工作者来说&#xff0…

python-模块-网络编程-多任务

一、模块 1-1 Python 自带模块 Json模块 处理json数据 {"key":"value"} json不是字典 本质是一个有引号的字符串数据 json注意点 {} 中的数据是字符串引号必须是双引号 使用json模块可以实现将json转为字典&#xff0c;使用字典的方法操作数据 。 或者将…

【为什么 Google Chrome 打开网页有时极慢?尤其是国内网站,如知网等】

要通过知网搜一点资料&#xff0c;发现怎么都打不开。而且B站&#xff0c;知乎这些速度也变慢了&#xff01;已经检查过确定不是网络的问题。 清空了记录&#xff0c;清空了已接受Cookie&#xff0c;清空了缓存内容……没用&#xff01;&#xff01;&#xff01; 不断搜索&am…

3D模型太大转换为线形3d渲染中为什么显示不出来?---模大狮模型网

在3D设计和渲染过程中&#xff0c;有时会遇到模型过大的情况&#xff0c;为了提高软件的响应速度和工作效率&#xff0c;将模型转换为线性模式是一种常见的解决方法。然而&#xff0c;有时在转换为线性模式后&#xff0c;可能会出现模型无法显示的问题。本文将探讨在3D渲染中将…

3、css3 手写nav导航条(互相学习)

效果例图&#xff1a; 1、首先呈现的是html代码&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><…

LabVIEW车体静强度试验台测控系统

LabVIEW车体静强度试验台测控系统 开发了一种基于LabVIEW的车体静强度试验台测控系统&#xff0c;通过自动化技术提高试验的精度和效率。系统采用LabVIEW软件与S7-200 SMART PLC硬件平台相结合&#xff0c;实现了对液压缸作用力的精确控制和试验数据的实时采集及管理。 传统的…

高德地图 JS API用于绘画船舶轨迹

文章目录 引言I 2.0升级指南1.1 修改 JSAPI 引用中的版本号到 2.01.2 相应修改II 1.4.15 文档引言 地图 JS API 2.0 是高德开放平台免费提供的第四代 Web 地图渲染引擎, 以 WebGL 为主要绘图手段,本着“更轻、更快、更易用”的服务原则,广泛采用了各种前沿技术,交互体验、…

【SQL学习进阶】从入门到高级应用【三范式】

文章目录 什么是数据库设计三范式三范式一对多怎么设计多对多怎么设计一对一怎么设计最终的设计 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f495;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f495;希望您在这里可以感受到一份…

【学习笔记】计算机组成原理(九+十)

控制单元的功能 文章目录 控制单元的功能9.1 微操作命令的分析9.1.1 取指周期9.1.2 间址周期9.1.3 执行周期9.1.4 中断周期 9.2 控制单元的功能9.2.1 控制单元的外特性9.2.2 控制信号举例9.2.3 多级时序系统9.2.4 控制方式 控制单元的设计10.1 组合逻辑设计10.1.1 组合逻辑控制…

结构体 基础知识

本笔记为观看64 结构体-结构体定义和使用_哔哩哔哩_bilibili 的学习笔记 1.结构体概念 结构体属于用户自定义的数据类型&#xff0c;允许用户存储不同的数据类型。 2.结构体定义和使用 ​ 结构体定义 ​ 通过结构体创建变量的方式 2.1 Struct 结构体名 变量名 ​ 2…

“仿RabbitMQ实现消息队列”---整体架构与模块说明

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、概念性框架理解 我们主要实现的内容&#xff1a; 1.Broker服务器&#xff1a;消息队列服务器&#xff08;服务端&…

使用 Scapy 库编写源路由攻击脚本

一、介绍 源路由攻击是一种网络攻击方法&#xff0c;攻击者通过利用IP数据包中的源路由选项来控制数据包的传输路径&#xff0c;从而绕过安全设备或防火墙&#xff0c;直接访问目标系统。源路由功能允许数据包的发送方指定数据包通过的路径&#xff0c;而不是由路由器根据路由…

达梦数据库(六) -------- 数据迁移MYSQL->达梦数据库

前言&#xff1a;确保安装好达梦数据库&#xff0c;达梦数据库(三) -------- 安装和初始化达梦数据库_达梦数据库安装-CSDN博客&#xff0c;需要安装达梦的数据库软件包&#xff0c;直接安装达梦8是包含这个功能的。安装包下载地址如下需要注册&#xff1a; https://www.damen…