展开说说:Android四大组件之Service使用

Service一定要开启子线程才可以执行耗时任务吗?不完全是吧。

Service是Android系统中的四大组件之一,它是一种没有可视化界面,运行于后台的一种服务程序属于计算型组件,用来在后台执行持续性的计算任务,重要性仅次于Activity活动。

本文分四块来记录,分别是普通Service、IntentService、ForegroundService,其中普通service根据运行状态不同分为startService启动的Service和bindService绑定的Service。

先定义一个Service子实现类,普通Service的启动的Service和bindService绑定的Service共用这一个Service类。

public class ServiceJia extends Service {
    private static final String TAG = ServiceJia.class.getName();
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: " );
        return new JiaBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: " );
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG, "onStartCommand: " );

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(30000);
                    Log.e(TAG, "onStartCommand:    等了半分钟" );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Log.e(TAG, "onStartCommand:    -end" );
        return super.onStartCommand(intent, flags, startId);
    }

//用于bindService时和activity交互
    public static class JiaBinder extends Binder {
        public void doSomething(String something){
            Log.e(TAG, "JiaBinder  --doSomething: "+something );
        }

        public void onClick(String something){
            Log.e(TAG, "JiaBinder  --onClick: "+something );
        }
    }

}

1、startService启动Service和停止

通过startService()创建启动的service可以一直运行下去,必须自己调用stopSelf()方法或者其他组件调用stopService()方法来停止。适用于不和其他组件通讯的业务。

 //不可以阻塞线程做耗时操作,比如这样:

try {
     Thread.sleep(30000);
     } catch (InterruptedException e) {
           e.printStackTrace();
      }
 程序闪退报错:
2023-12-02 09:46:39.584 1592-1795/? E/ActivityManager: ANR in com.example.testdemo3 PID: 29467
Reason: executing service com.example.testdemo3/.service.ServiceJia
Load: 46.58 / 46.1 / 46.01
CPU usage from 70164ms to 0ms ago (2023-12-02 09:45:28.698 to 2023-12-02 09:46:38.862) with 99% awake:

启动和关闭服务:

startService.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String text = startService.getText().toString();
        if ("startService".equals(text)){
            startService.setText("stopService");
            serviceIntent = new Intent(ServiceActivity.this, ServiceJia.class);
            startService(serviceIntent);
        }else if ("stopService".equals(text)){
            if (stopService(serviceIntent)){ //真停了再修改按钮的文字显示
                startService.setText("startService");
            }
        }

    }
});

2、bindService绑定Service和解绑

调用bindService()来创建,调用方可以通过一个IBinder接口和service进行通信,需要通过ServiceConnection建立连接多用于有交互的场景。

只能调用方通过unbindService()方法来断开连接。调用方可以和Service通讯,并且一个service可以同时和多个调用方存在绑定关系解除绑定也需要所有调用全部解除绑定之后系统会销毁service

绑定和解绑服务:

String text = bindService.getText().toString();
if ("bindService".equals(text)){
if (serviceIntent == null)
    serviceIntent = new Intent(ServiceActivity.this, ServiceJia.class);
    if (bindService(serviceIntent,serviceConnection, Context.BIND_AUTO_CREATE)){
        bindService.setText("unBindService");
    }
}else if ("unBindService".equals(text)){
    unbindService(serviceConnection);
    bindService.setText("bindService");
}

//连接成功,可以通过Binder调用绑定的service中的方法,比如jiaBinder.doSomething("start conncetion");

serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Log.e(TAG, "onServiceConnected: " );
        jiaBinder = (ServiceJia.JiaBinder) iBinder;
        //连接成功,调用绑定的service中的方法
        jiaBinder.doSomething("start conncetion");
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Log.e(TAG, "onServiceDisconnected: " );
    }

    @Override
    public void onBindingDied(ComponentName name) {
        Log.e(TAG, "onBindingDied: " );
    }

    @Override
    public void onNullBinding(ComponentName name) {
        Log.e(TAG, "onNullBinding: " );
    }
};

3、IntentService

它可以解决第一句中“Service一定要开启子线程才可以执行耗时任务吗?”的问题。

IntentService 是 Android 中的一个服务,继承自 Service 类,并在单独的工作线程中执行任务,避免了多线程处理异步任务我们可以在onHandleIntent生命周期方法中执行耗时任务,不用开启子线程:

注意这里是继承IntentService

还有就是继承IntentService必须声明一个空参构造方法否则会报错删除 

public class MyIntentService extends IntentService {
    public static final String TAG = "MyIntentService";
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     * @param name Used to name the worker thread, important only for debugging.
     * 如果name字段为空,字符串就是worker thread的名字
     */
    public MyIntentService(String name) {
        super(name);
    }

    public MyIntentService() {
        super(TAG);

    }

    /**
     * 可以做耗时任务
     * @param intent
     */
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        String type = intent.getStringExtra("type");
        try {
            Log.e(TAG, "onHandleIntent:  -start" );
            Thread.sleep(10000);
            Log.e(TAG, "onHandleIntent:  -end" );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

启动和关闭IntentService

intentService.setOnClickListener(new View.OnClickListener() {
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onClick(View v) {

        String text = intentService.getText().toString();
        if ("startIntentService".equals(text)){
            intentService.setText("stopIntentService");
            intentServiceIntent = new Intent(ServiceActivity.this, MyIntentService.class);
            startService(intentServiceIntent);
        }else if ("stopIntentService".equals(text)){
            boolean b = stopService(intentServiceIntent);
            Log.e(TAG, "onClick: stopIntentService= "+b );
            if (b){ //真停了再修改按钮的文字显示
                intentService.setText("startIntentService");
            }
        }
    }
});

这里有一个比较坑的地方就是,必须指定一个空参构造函数,否则运行就会报错。

4、前台服务

前台服务用于执行用户可察觉的操作。前台服务会显示状态栏通知,让用户知道当前应用正在前台执行任务并消耗系统资源。用户可以通过点击通知来与应用进行交互。

值得注意的两个点:

  • 除了在AndroidManifest.xml注册服务之外,还需要申请前台服务的权限,否则会闪退。

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

  • Build.VERSION_CODES.O及以上的系统,需要单独NotificationManager需要设置NotificationChannel否则会闪退,具体见下面代码。

闪退报错信息:“android.app.RemoteServiceException: Bad notification for startForeground

使用上和普通Service类似同样继承Service,但是要设置前台服务通知

startForeground(1000,notification);

定义前台服务:
public class MyForegroundService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Notification.Builder builder = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            builder = new Notification.Builder(this,getChannelId("com.example.testdemo.service","MyForegroundService"));
            Notification notification = builder.setContentTitle("我是前台服务")
                    .setContentText("目前运行平稳")
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .build();
            //设置前台服务
            startForeground(1000,notification);
        }else {
            //设置前台服务
            startForeground(1000,new Notification());
        }
        //被杀以后还会再次创建
        return START_STICKY;
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private String getChannelId(String channelId, String channelName) {
        NotificationChannel notificationChannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE);
        notificationChannel.setLightColor(Color.BLUE);
        notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(notificationChannel);
        return channelId;
    }
}

启动和关闭前台服务:

 foregroundService.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(View v) {
                String text = foregroundService.getText().toString();
                if ("startForegroundService".equals(text)){
                    foregroundService.setText("stopForegroundService");
                    foregroundServiceIntent = new Intent(ServiceActivity.this, MyForegroundService.class);
//                    startService(intentServiceIntent);
                    startForegroundService(foregroundServiceIntent);
                }else if ("stopForegroundService".equals(text)){
                    boolean b = stopService(foregroundServiceIntent);
                    Log.e(TAG, "onClick: stopIntentService= "+b );
                    if (b){ //真停了再修改按钮的文字显示
                        foregroundService.setText("startForegroundService");
                    }
                }
            }
        });

本文主要是记录了四种使用服务经常遇到的问题,后面再分析生命周期和源码。

才疏学浅,如有错误,欢迎指正,多谢。

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

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

相关文章

2024亚太杯中文赛数学建模选题建议及各题思路来啦!

大家好呀&#xff0c;2024年第十四届APMCM亚太地区大学生数学建模竞赛&#xff08;中文赛项&#xff09;开始了&#xff0c;来说一下初步的选题建议吧&#xff1a; 首先定下主基调&#xff0c; 本次亚太杯推荐大家选择B题目。C题目难度较高&#xff0c;只建议用过kaiwu的队伍…

决策树算法的原理与案例实现

一、绪论 1.1 决策树算法的背景介绍 1.2 研究决策树算法的意义 二、决策树算法原理 2.1 决策树的基本概念 2.2 决策树构建的基本思路 2.2 决策树的构建过程 2.3 决策树的剪枝策略 三、决策树算法的优缺点 3.1 决策树算法的优势 3.2 决策树算法的局限性 3.3 决策树算…

微服务粒度难题:找到合适的微服务大小

序言 在微服务架构风格中&#xff0c;微服务通常设计遵循SRP&#xff08;单一职责原则&#xff09;&#xff0c;作为一个独立部署的软件单元&#xff0c;专注于做一件事&#xff0c;并且做到极致。作为开发人员&#xff0c;我们常常倾向于在没有考虑为什么的情况下尽可能地将服…

全面教程:在Ubuntu上快速部署ZeroTier,实现Windows与VSCode的局域网无缝访问

文章目录 1 背景介绍2 Windows上的操作3 Ubuntu上的操作4 连接 1 背景介绍 在现代工作环境中&#xff0c;远程访问公司内网的Ubuntu主机对于开发者来说是一项基本需求。然而&#xff0c;由于内网的限制&#xff0c;传统的远程控制软件如向日葵和todesk往往无法满足这一需求。作…

二叉树之遍历

二叉树之遍历 二叉树遍历遍历分类前序遍历流程描述代码实现 中序遍历流程描述代码实现 后序遍历流程描述代码实现 层次遍历流程描述代码实现 总结 二叉树遍历 遍历分类 遍历二叉树的思路有 4 种&#xff0c;分别是&#xff1a; 前序遍历二叉树&#xff0c;有递归和非递归两种…

用dify实现简单的Agent应用(AI信息检索)

这篇文章里&#xff0c;我们来聊聊如何使用字节最新的豆包大模型&#xff0c;在 Dify 上来快速完成一个具备理解需求、自主规划、自主选择工具使用的简单智能体&#xff08;Agent&#xff09;。 准备工作 完整准备过程分为&#xff1a;准备 Docker 环境、启动 Dify 程序、启动…

线性代数基础概念:矩阵

目录 线性代数基础概念&#xff1a;矩阵 1. 矩阵的定义 2. 矩阵的运算 3. 矩阵的特殊类型 4. 矩阵的秩 5. 矩阵的初等变换 6. 矩阵的特征值与特征向量 7. 矩阵的应用 8. 矩阵总结 总结 线性代数基础概念&#xff1a;矩阵 矩阵是线性代数中的另一个重要概念&#xff0…

vue目录说明

vue目录说明 主要目录说明 .vscode - - -vscode工具的配置文件夹 node_modules - - - vue项目的运行依赖文件夹 public - - -资源文件夹&#xff08;浏览器图标&#xff09; src- - -源码文件夹 .gitignore - - -git忽略文件 index.html - - -入口html文件 package.json - - -…

windows搭建mqtt服务器,并配置DTU收集传感器数据

1.下载并安装emqx服务器 参考&#xff1a;Windows系统下本地MQTT服务器搭建&#xff08;保姆级教程&#xff09;_mqtt windows-CSDN博客 这里我下载的是emqx-5.3.0-windows-amd64.zip版本 下载好之后&#xff0c;放到服务器的路径&#xff0c;我这里放的地方是&#xff1a;C…

图像信号处理器(ISP)基础算法及处理流程

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

FreeRTOS之队列上锁和解锁(详解)

这篇文章将记录我学习实时操作系统FreeRTOS的队列上锁和解锁的知识&#xff0c;在此分享给大家&#xff0c;希望我的分享能给你带来不一样的收获&#xff01; 目录 一、简介 二、队列上锁函数prvLockQueue&#xff08;&#xff09; 1、函数初探 2、应用示例 三、队列解锁函…

转让北京文化传媒公司带营业性演出经纪许可证

影视文化传播倡导将健康的影视文化有效传播给观众&#xff0c;从而构建观众与电影制作者的良 性沟通与互动&#xff0c;是沟通电影制作者与电影受众的重要桥梁。影视文化泛指以电影&#xff0c;电视方式所进行的全部文化创造&#xff0c;即体现为电影&#xff0c;电视全部的存在…

找不到msvcp120.dll无法继续执行的原因分析及解决方法

在计算机使用中&#xff0c;经常会遇到msvcp120.dll文件丢失的情况&#xff0c;很多人对这个文件不是很熟悉&#xff0c;今天就来给大家讲解一下msvcp120.dll文件的丢失以及这个文件的重要性&#xff0c;让大家更好地了解计算机&#xff0c;同时也可以帮助我们更好地掌握这个文…

航模插头篇

一、常见的电池插头&#xff08;电调端 是公头 电池端 是母头&#xff09; 电池总是被插的 1.XT60头 过流大 安全系数高 难插拔 2.T插 插拔轻松 过流比较小 容易发烫 电调端 是公头 电池端 是母头 3.香蕉头插孔 过流够 插拔轻松 但 容易插反 爆炸 4.TX90(和XT60差…

2024 年 亚太赛 APMCM (A题)中文赛道国际大学生数学建模挑战赛 | 飞行器外形的优化 | 数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题&#xff01; 完整内容可以在文章末尾领取&#xff01; 第一个问…

C++内存管理(候捷)第一讲 笔记

内存分配的每一层面 applications可以调用STL&#xff0c;里面会有allocator进行内存分配&#xff1b;也可以使用C 基本工具primitives&#xff0c;比如new, new[], new(), ::operator new()&#xff1b;还可以使用更底层的malloc和free分配和释放内存。最底层的是系统调用&…

明星代言6个提升企业形象的杀手锏-华媒舍

在当今竞争激烈的商业世界中&#xff0c;企业形象的塑造对于品牌的发展至关重要。而明星代言作为一种常见的营销手段&#xff0c;被广泛使用来提升企业形象和产品销售。本文将介绍明星代言的六个杀手锏&#xff0c;帮助您了解如何通过明星代言来提升企业形象。 1. 拥有广泛的影…

十二、【源码】Spring整合AOP

源码地址&#xff1a;https://github.com/spring-projects/spring-framework 仓库地址&#xff1a;https://gitcode.net/qq_42665745/spring/-/tree/12-spring-aop Spring整合AOP 核心类&#xff1a; DefaultAdvisorAutoProxyCreator&#xff1a;用于在Spring框架中自动为符…

若依多数据源原理分析

首先&#xff0c;想明白不同的接口想要使用不同的数据源。 那么自然想到了AOP&#xff0c;自定义注解。 通过自定义注解标注当前方法到底使用的是哪个数据源。 上面是前置条件。 看下若依是怎么处理的&#xff1a; 1.定义自定义注解&#xff0c;以及对应的多数据源的枚举类…

天润融通分析AI技术助力客户服务,实现满意度三倍增长

如今&#xff0c;客户体验越来越成为影响客户决策的核心要素。 对于企业来讲&#xff0c;客户在不同触点的每一次互动体验&#xff0c;都成为塑造品牌声誉的“Aha时刻”。但同时&#xff0c;随着社会的发展的加速&#xff0c;客户的需求也在日新月异&#xff0c;给企业带来挑战…