深入分析 Android Service (完)

news2025/1/23 4:59:17

文章目录

    • 深入分析 Android Service (完)
    • 1. Service 的生命周期管理
    • 2. Service 的生命周期方法
      • 2.1 onCreate()
      • 2.2 onStartCommand(Intent intent, int flags, int startId)
      • 2.3 onBind(Intent intent)
      • 2.4 onUnbind(Intent intent)
      • 2.5 onRebind(Intent intent)
      • 2.6 onDestroy()
    • 3. Service 重启策略
    • 4. 使用 Service 进行前台任务
    • 5. 实现前台服务示例
      • 5.1 创建前台服务
      • 5.2 启动前台服务
    • 6. Service 的优化和调试
      • 6.1 使用 JobScheduler 替代传统 Service
      • 6.2 使用 WorkManager 处理后台任务
      • 6.3 调试和监控
    • 7. 示例代码汇总
      • 7.1 服务端代码(Messenger)
      • 7.2 客户端代码(Messenger)
      • 7.3 服务端代码(AIDL)
      • 7.4 客户端代码(AIDL)
    • 8. 总结

深入分析 Android Service (完)

1. Service 的生命周期管理

Service 的生命周期管理是确保 Service 能够正确启动、运行、停止和清理资源的关键。理解 Service 的生命周期方法可以帮助开发者更好地管理和优化 Service

2. Service 的生命周期方法

Service 的主要生命周期方法包括:

  1. onCreate()
  2. onStartCommand(Intent intent, int flags, int startId)
  3. onBind(Intent intent)
  4. onUnbind(Intent intent)
  5. onRebind(Intent intent)
  6. onDestroy()

2.1 onCreate()

Service 被创建时调用。通常在这里初始化任何必要的资源。

@Override
public void onCreate() {
    super.onCreate();
    // 初始化资源,如线程池、数据库连接等
}

2.2 onStartCommand(Intent intent, int flags, int startId)

在每次通过 startService() 方法启动 Service 时调用。此方法是处理实际业务逻辑的主要入口。返回值决定系统如何在服务因内存不足而被杀死后重启它。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // 处理业务逻辑,如下载文件、播放音乐等
    return START_STICKY;  // START_NOT_STICKY, START_REDELIVER_INTENT, or START_STICKY_COMPATIBILITY
}

2.3 onBind(Intent intent)

在客户端绑定到 Service 时调用。返回一个 IBinder 对象,用于与客户端通信。

@Override
public IBinder onBind(Intent intent) {
    // 返回通信接口
    return binder;
}

2.4 onUnbind(Intent intent)

在所有客户端都解绑时调用。通常在这里清理与绑定相关的资源。

@Override
public boolean onUnbind(Intent intent) {
    // 清理绑定相关资源
    return super.onUnbind(intent);
}

2.5 onRebind(Intent intent)

在之前调用了 onUnbind() 后,新的客户端再次绑定到 Service 时调用。

@Override
public void onRebind(Intent intent) {
    super.onRebind(intent);
}

2.6 onDestroy()

Service 被销毁前调用。通常在这里清理所有资源。

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

3. Service 重启策略

onStartCommand 方法的返回值决定了当 Service 因系统内存不足被杀死后,系统如何重启它:

  • START_STICKY:服务被系统终止后会自动重启。Intent 不会保留,意味着数据不会保留,但服务会继续运行。
  • START_NOT_STICKY:服务被系统终止后不会自动重启,除非有新的 Intent。
  • START_REDELIVER_INTENT:服务被系统终止后会自动重启,并重传最后一个 Intent。
  • START_STICKY_COMPATIBILITY:类似于 START_STICKY,但用于兼容低版本。

4. 使用 Service 进行前台任务

为了确保 Service 在后台运行时不被系统终止,可以将 Service 提升为前台服务。这可以通过调用 startForeground() 方法实现,并提供一个持续显示的通知。

5. 实现前台服务示例

5.1 创建前台服务

public class ForegroundService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        Notification notification = createNotification();
        startForeground(1, notification);
    }

    private Notification createNotification() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String channelId = "foreground_service_channel";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, "Foreground Service Channel", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                .setContentTitle("Foreground Service")
                .setContentText("Service is running in the foreground")
                .setSmallIcon(R.drawable.ic_service_icon);
        return builder.build();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 处理业务逻辑
        return START_STICKY;
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
    }
}

5.2 启动前台服务

Activity 中启动前台服务:

Intent intent = new Intent(this, ForegroundService.class);
startService(intent);

6. Service 的优化和调试

为了优化 Service 的性能和可靠性,可以采用以下方法:

6.1 使用 JobScheduler 替代传统 Service

对于需要在特定条件下运行的任务,推荐使用 JobScheduler,它可以根据系统资源和条件优化任务的执行时间。

JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(this, MyJobService.class))
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .setRequiresCharging(true)
        .build();
jobScheduler.schedule(jobInfo);

6.2 使用 WorkManager 处理后台任务

WorkManager 提供了一种现代化的任务调度机制,适用于需要保证任务执行的场景。它可以自动处理任务的重试和约束条件。

OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
        .setConstraints(new Constraints.Builder().setRequiresCharging(true).build())
        .build();
WorkManager.getInstance(this).enqueue(workRequest);

6.3 调试和监控

使用 StrictMode 检测潜在的性能问题,如磁盘读写和网络访问:

if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .build());
}

利用 Android Studio 的 Profiler 工具监控 Service 的 CPU、内存和网络使用情况,以识别和解决性能瓶颈。

7. 示例代码汇总

7.1 服务端代码(Messenger)

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();
    }
}

7.2 客户端代码(Messenger)

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;
        }
    }
}

7.3 服务端代码(AIDL)

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;
    }
}

7.4 客户端代码(AIDL)

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;
        }
    }
}

8. 总结

通过合理设计和优化 Android Service,可以确保应用在后台高效、稳定地运行,提供良好的用户体验。希望本系列文章能够帮助开发者更深入地理解 Service 的工作机制和优化策略,为开发高质量的 Android 应用提供参考和指导。

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在当前页面拿到抽屉弹窗页面中从后端返回的值 #Vue3 #两个.vue页面之间传值问题

在当前页面拿到抽屉弹窗页面中从后端返回的值 #Vue3 #两个.vue页面之间传值问题 *解决方法一: 将抽屉弹窗里从后端返回得到的值缓存在浏览器中,在当前页面中从浏览器中获取该值。 (原理其实就是借助第三个盒子来传递一下值,太小学…

钣金件设计规范

(一) 钣金 1、钣金的概念 钣金(sheet metal)是针对金属薄板(厚度通常在6mm以下)的 一种综合冷加工工艺,包括冲裁、折弯、拉深、成形、锻压、铆合等, 其显著的特征是同一零件厚度一致。 2、钣…

【代码审计】star7th/showdoc:v3.2.4 Phar反序列化写webshell

目录 漏洞速览 复现 漏洞速览 微步在线X情报社区-威胁情报查询_威胁分析平台_开放社区 主要就是两步,sql注入拿到用户token,再以用户身份上传恶意phar包打phar反序列化 因为文件上传对用户权限没有限制,故本文对sql注入部分不做探讨。…

Python SMTP配置示例:如何群发邮件列表?

Python SMTP配置的高级技巧?API接口的正确使用方法? Python的SMTP库为我们提供了一种简单而强大的方式来实现邮件的群发功能。Aok将通过一个示例,向您展示如何使用Python SMTP配置来群发邮件列表,并在此过程中提及AokSend邮件API…

MulterError: Field name missing 报错解决

Request POST /FileUpload/chunkApi/upload/mProjectNews/Images failed with status code 500. MulterError: Field name missing. 原因:Multer是基于Busboy解析的表单参数信息,经定位发现是解析表单中文本参数时出现了null,故收到MISSION_…

掌握 NestJS 10.x:NestJS 结合 PostgreSQL 使用详解

NestJS 是一个用于构建高效、可扩展的 Node.js 服务端应用的框架。结合 PostgreSQL 数据库,可以为应用提供强大的数据存储和查询功能。本文将详细介绍如何在 NestJS 项目中集成和使用 PostgreSQL,并创建一个包含增加用户接口的完整示例。 1. 安装必要的依赖 首先,确保你的…

自动驾驶仿真:python和carsim联合仿真案例

文章目录 前言一、Carsim官方案例二、Carsim配置1、车辆模型2、procedure配置3、Run Control配置 三、python编写四、运行carsim五、运行python总结 前言 carsim内部有许多相关联合仿真的demo,simulink、labview等等都有涉及,这里简单介绍下python和car…

【一百零五】【算法分析与设计】分解质因数,952. 按公因数计算最大组件大小,204. 计数质数,分解质因数,埃式筛

分解质因数 题目&#xff1a;分解质因数 题目描述 给定一个正整数 n&#xff0c;编写一个程序将其分解为质因数&#xff0c;并按从小到大的顺序输出这些质因数。 输入格式 一个正整数 n&#xff0c;其中 n 的范围是 1 < n < 10^18。 输出格式 按从小到大的顺序输出 n 的质…

echarts legend. icon的展示

默认展示 icon展示circle圆形rect矩形roundRect圆角矩形triangle三角形diamond菱形pin水滴arrow箭头none不显示

Linux C语言:输入输出(printf scanf)

一、数据输出 1、C语言I/O操作由函数实现 #include <stdio.h> 2、字符输出函数 格式: int putchar( int c ) 参数: c为字符常量、变量或表达式 功能&#xff1a;把字符c输出到显示器上 返值&#xff1a;putchar函数的返回值是参数的ASCLL码值&#xff1b; #inclu…

蓝牙网关是什么?能做什么?

蓝牙网关是一种集成了蓝牙通信技术的设备&#xff0c;它在物联网&#xff08;IoT&#xff09;和其他无线通信场景中扮演着重要的角色。以下是蓝牙网关的基本概念以及它的主要功能和应用场景&#xff1a; 蓝牙网关是什么&#xff1f; 蓝牙网关是一种设备&#xff0c;它能够将蓝…

什么是通配符SSL证书?要怎么申请?

通配符SSL证书的作用主要是为了方便管理和加密具有多个子域名的网站。它能够保护一个主域名及其所有的同级子域名&#xff0c;无论子域名的数量多少或名称如何变化。使用一个通配符证书&#xff0c;你可以为像 *.example.com 这样的设置加密&#xff0c;这样不论是 blog.exampl…

使用kubespray部署k8s生产环境

使用kubespray部署k8s生产环境 系统环境 OS: Static hostname: test Icon name: computer-vm Chassis: vm Machine ID: 22349ac6f9ba406293d0541bcba7c05d Boot ID: 83bb7e5dbf27453c94ff9f1fe88d5f02 Virtualization: vmware Operating System: Ubuntu 22.04.4 LTS Kernel: L…

【成品设计】基于华大hc32F005c6ua的读取NFC卡

《基于华大hc32F005c6ua的读取NFC卡》 整体功能&#xff1a; 单片机:华大hc32F005c6ua 1、支持单片机spi接口读取nfc读卡器芯片rc522读写数据 2、读取到的数据可以通过单片机uart接口通信&#xff0c;上报给上位机&#xff08;485主机&#xff09; 3、uart接口支持modbus协议…

飞腾D2000+FPGA云终端,实现从硬件、操作系统到应用的完全国产、自主、可控

飞腾云终端基于国产化飞腾高性能8核D2000处理器平台的国产自主可控解决方案&#xff0c;搭载昆仑国产化固件,支持UOS、银河麒麟等国产操作系统&#xff0c;满足国产化信息安全运算的需求&#xff0c;实现从硬件、操作系统到应用的完全国产、自主、可控&#xff0c;是国产信息安…

【优选算法】BFS解决FloodFill算法

一、经验总结 什么是FloodFill算法&#xff1f; FloodFill算法是一种用于填充连通区域的算法&#xff0c;通常用于图像处理和计算机图形学中。它从给定的起始点开始&#xff0c;向周围相邻的像素进行扩散填充&#xff0c;直到遇到边界或者其他指定条件停止。 FloodFill算法还…

【权威发布】2024年经济发展与社会科学国际会议(ICEDSS 2024)

2024年经济发展与社会科学国际会议 2024 International Conference on Economic Development and Social Sciences 【1】会议简介 2024年经济发展与社会科学国际会议是一个全球性的学术盛会&#xff0c;汇聚了世界各地的经济学家、社会学家及相关领域的专家学者。本次会议旨在提…

flink 作业报日志类冲突的解决方案

文章目录 背景思考初步解决方案深入思考下终极解决方案总结 背景 实时作业在页面提交任务后&#xff0c;报NoSuchMethodException 方法&#xff0c;看了下是关于log4j的&#xff0c;首先是作业升级了很多依赖的版本&#xff0c;其次flink 也升级 到了1.19版本 思考 打的Jar有…

影响指挥中心操作台的材质选择的因素有哪些

指挥中心操作台作为现代指挥系统的重要组成部分&#xff0c;其材质的选择不仅关系到操作台的使用寿命和稳定性&#xff0c;更直接影响到整个指挥中心的运行效率和安全性。因此&#xff0c;对指挥中心操作台的材质设定一系列标准显得尤为重要。 耐用性考量&#xff1a;鉴于指挥中…

10Linux 进程管理学习笔记

Linux 进程管理 目录 文章目录 Linux 进程管理一.进程1.显示当前进程状态(ps)进程树(pstree)1.1实时显示进程信息(top)顶部概览信息&#xff1a;CPU 状态&#xff1a;内存状态&#xff1a;进程信息表头&#xff1a;进程列表&#xff1a;1.2(htop) 2.终止进程(kill)2.1通过名称…