Service服务在Android中的使用

news2024/9/21 10:18:00

目录

一,Service简介

 二,Service的两种启动方式

1,非绑定式启动Service

2,绑定式启动Service

三,Service的生命周期

1,非绑定式Service的生命周期

2,绑定式Service的生命周期

四,前台Service

1,前台Service的创建

2,前台Service的结束


一,Service简介

        Service服务,是指执行指定系统功能的程序,例程或进程,以便支持其他程序,并且运行期间用户不可见的一种活动机制,例如:后台播放音乐,后台下载等;

        Service和Activity同属于一个级别,不同于子线程,service是运行在主线程中的,因此不能进行耗时操作;

 二,Service的两种启动方式

(1)非绑定式启动(startService):

  • 服务开启后与启动者没有任何关系,service的生命周期独立于启动者,启动者退出,service仍会运行;
  • 启动者无法调用service中的方法;

(2)绑定式启动(bindService)

  • 启动者(Activity)会和service绑定在一起,两者的生命周期会同步,当启动者退出时,service会跟着被销毁;
  • 启动者可以调用service中的方法;

1,非绑定式启动Service

(1) 创建一个类继承Service类,并重写一系列方法:

public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("MyService", "onBind: ");
        return null;
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService", "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.i("MyService", "onDestroy: ");
        super.onDestroy();
    }
}

(2)在Manifest文件中注册指定Service:

(3)调用startService(Intent intent)方法启动Service:

private void startMyService() {
    Intent intent = new Intent(this, MyService.class);
    startService(intent);
}

2,绑定式启动Service

(1)前两步与非绑定式启动一致,创建Service子类并注册Service:

public class MyBindService extends Service {
    private final String TAG = "MyBindService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return new MyBinder(this);
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind: ");
        return super.onUnbind(intent);
    }
}

(2)绑定式启动Service需要调用bindService()方法,这个方法需要三个参数:

private void startBindService() {
    Intent intent = new Intent(this, MyBindService.class);
    isBound = bindService(intent, connection, BIND_AUTO_CREATE);
}

Intent:表示启动意图,也就是想要启动的Service;

connection:相当于启动者(Activity)和Service之间的连接,通过一系列的回调函数来监听访问者和Service的连接情况;

int flag:绑定时是否自动创建Service,这里选择自动创建BIND_AUTO_CREATE;

        除了Intent和flag外,我们还需创建一个connection,这里通过匿名内部类的形式创建,并重写两个回调方法。这里onServiceConnected方法中有一个IBinder类型的service,这个service起到了中间人的作用,通过这个service,启动者(Activity)就可以调用Service中的方法:

private ServiceConnection connection = new ServiceConnection() {
    //创建连接时回调
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //这里 IBinder类型的service 就是我们要绑定的那个service
        //通过这个service,Activity就可以调用MyBindService.MyBinder中的方法
    }
    //断开连接时回调
    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.i(TAG, "onServiceDisconnected: ");
    }
};

        那么这个service是从哪来的呢?

        在我们创建的Service子类中,我们重写了一个onBind的方法,返回的正好是一个IBinder类型的值,这个返回值也就是会传给上面service的值。

@Override
public IBinder onBind(Intent intent) {
    Log.i(TAG, "onBind: ");
    return new MyBinder(this);
}

        所以我们可以在Service子类中创建一个类继承自Binder(Binder实现了IBinder接口),这样Activity通过connection中的service就可以调用MyBinder类中的方法;

        进一步,通过构造方法,我们可以将Service传给MyBinder,这样在MyBinder中就可以调用我们Service中的方法,又因为Activity可以调用MyBinder中的方法,所以我们就实现了Activity调用Service的方法,这也就是为什么绑定式启动Service,启动者(Activity)可以调用Service中的方法;

@Override
public IBinder onBind(Intent intent) {
    Log.i(TAG, "onBind: ");
    return new MyBinder(this);
}

public void Test(){
    //Log.i(TAG, "Test: MyBindService的Test方法被调用");
}

public class MyBinder extends Binder{
    private MyBindService myBindService;
    public MyBinder(){}
    public MyBinder(MyBindService bindService){
        this.myBindService = bindService;
    }
    public void Test(){
        //Log.i(TAG, "Test: MyBinder的Test方法被调用");
        //这样MyBinder就可以调用MyBindService中的方法
        //MyBinder作为一个中间人 Activity调用MyBinder的方法 -> MyBinder再调用Service的方法
        myBindService.Test();
    }
}

绑定式启动Service的全部流程代码:

Activity

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";

    private Boolean isBound = false;

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setLinsteners();
    }

    private void setLinsteners() {
        binding.btnStartBindService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startBindService();
            }
        });
    }

    private void startBindService() {
        Intent intent = new Intent(this, MyBindService.class);
        isBound = bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private MyBindService.MyBinder myBindService;

    private ServiceConnection connection = new ServiceConnection() {
        //创建连接时回调
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //这里 IBinder类型的service 就是我们要绑定的那个service
            //通过这个service,Activity就可以调用MyBindService.MyBinder中的方法
            myBindService = (MyBindService.MyBinder)service;
            myBindService.Test();
        }
        //断开连接时回调
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: ");
            //Intent intent = new Intent(MainActivity.this, MyBindService.class);
            //stopService(intent);
        }
    };
}

Service

public class MyBindService extends Service {

    private final String TAG = "MyBindService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return new MyBinder(this);
    }

    public void Test(){
        //Log.i(TAG, "Test: MyBindService的Test方法被调用");
    }

    public class MyBinder extends Binder{
        private MyBindService myBindService;
        public MyBinder(){}
        public MyBinder(MyBindService bindService){
            this.myBindService = bindService;
        }
        public void Test(){
            //Log.i(TAG, "Test: MyBinder的Test方法被调用");
            //这样MyBinder就可以调用MyBindService中的方法
            //MyBinder作为一个中间人 Activity调用MyBinder的方法 -> MyBinder再调用Service的方法
            myBindService.Test();
        }
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "onUnbind: ");
        return super.onUnbind(intent);
    }

}

三,Service的生命周期

1,非绑定式Service的生命周期

启动阶段:启动者(Activity)调用startService

  • onCreate():Service被创建时调用,整个生命周期中只会被调用一次;
  • onStartCommand():每次调用startService时,该方法会被调用,该方法接收Intent参数,从而可以执行一些命令;

结束阶段:启动者调用stopService()方法或Service内部调用stopSelf()方法;

  • onDestroy():Service销毁时调用,与onCreate一样,整个生命周期中只会被调用一次;

2,绑定式Service的生命周期

启动阶段:启动者(Activity)调用bindService

  • onCreate():Service被创建时调用,整个生命周期中只会被调用一次;
  • onBind():在首次绑定时会被调用一次,同样整个生命周期中只会被调用一次;

结束阶段:当启动者销毁或unBindService方法时,启动者会和Service解除绑定,当没有任何绑定者时,Service会被销毁

  • onUnbind():解除绑定时调用,可多次调用;
  • onDestroy():Service销毁时调用,整个生命周期中只会被调用一次;

四,前台Service

        前台Service,即可以与用户进行交互的运行在前台的Service,优先级相比于其他两种运行在后台的Service要高,最常见的应用就是通知栏前台控制音乐播放;

1,前台Service的创建

        在正常的Service中调用startForeground() 方法即可将正常服务提升为前台服务,startForeground()方法需要接收一个通知对象,因为前台Service必须在通知栏中进行通知;

public class MyForeGroundService extends Service {
    private final String TAG = "MyForeGroundService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return null;
    }

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

        //创建一个通知
        NotificationManager notificationManager = (NotificationManager) getApplication().getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(
                "channel_id",
                "channel_name",
                notificationManager.IMPORTANCE_HIGH
        );
        notificationManager.createNotificationChannel(channel);
        Notification.Builder builder = new Notification.Builder(
                this,
                "channel_id"
        );
        Notification notification = builder.build();
        //将服务提升为前台服务
        startForeground(1, notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

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

}

2,前台Service的结束

 前台Service的结束有两种含义:

(1)结束Service本身:通过启动者调用stopService方法或Service内部调用stopSelf方法正常结束Service,Service结束后,通知也会随之移除;

(2)前台Service降级为后台Service:通过Service内部调用stopForeground(true)方法将Service退出后台状态,此时Service不会被销毁,当内存不足时,Service可能会被回收。参数true表示移除通知;

前台Service创建和结束的全部流程代码:

Activity: 

public class MainActivity extends AppCompatActivity {

    private final String TAG = "MainActivity";

    private Boolean isBound = false;

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        setLinsteners();
    }

    private void setLinsteners() {
        //创建前台Service
        binding.btnStartForeGroundService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyForeGroundService.class);
                startService(intent);
            }
        });
        //移除前台Service
        binding.btnStopForeGroundService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyForeGroundService.class);
                intent.putExtra("key_stop", "stopForeGround");
                startService(intent);
            }
        });
    }
   
}

Service:

public class MyForeGroundService extends Service {

    private final String TAG = "MyForeGroundService";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind: ");
        return null;
    }

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

        //创建一个通知
        NotificationManager notificationManager = (NotificationManager) getApplication().getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(
                "channel_id",
                "channel_name",
                notificationManager.IMPORTANCE_HIGH
        );
        notificationManager.createNotificationChannel(channel);
        Notification.Builder builder = new Notification.Builder(
                this,
                "channel_id"
        );
        Notification notification = builder.build();
        //将服务提升为前台服务
        startForeground(1, notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand: ");
        String keyStop = intent.getStringExtra("key_stop");
        if(TextUtils.equals(keyStop, "stopForeGround")){
            stopForeground(true);//true表示移除通知
        }
        return super.onStartCommand(intent, flags, startId);
    }

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

}

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

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

相关文章

BCArchive加密工具实测分享:为何我觉得它很实用?

前言 你是不是经常有这样的烦恼:重要的文件、私密的照片、敏感的资料,总是担心会不小心泄露出去?哎呀,别担心,别担心,我今天要介绍的这款软件,简直就是守护你数据安全的超级英雄! 在…

CVE-2012-2122 mysql/mariaDB身份认证漏洞

简介: 当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,不断的尝试登录连接,回导致MySQL认为两个密码是相同的。也就是说只要知道用户名,不断尝试就能够直接登入SQL数据库。 影响范围#所有的Mariadb和mysql版…

【吊打面试官系列-Elasticsearch面试题】Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?

大家好,我是锋哥。今天分享关于 【Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?】面试题,希望对大家有帮助; Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法? 1、64 GB 内存…

【STM32】CubeMX + CLion + FreeRTOS移植过程问题记录

文章目录 一、portable 文件选择二、自定义文件添加三、ST-Link v2 烧录问题四、STM32F407工程中程序无法启动调度器 前言   本文依照稚晖君分享的配置CLion用于STM32开发【优雅の嵌入式开发】,尝试配置STM32CubeMX CLion开发环境,并在此基础上移植Fre…

利用Emgucv绘制条形码边框16(C#)

EmguCV环境配置: ​​​​​​Emgu CV4图像处理之环境搭建1(C#)_emgucv 4.7-CSDN博客 本文测试环境: win10 64位 vistual studio 2019 Emgu CV 4.6.0 环境配置准备: 1 新增控制台项目,.net framework为4.7.2 2 把win-x…

minikube 实践练习

前言 我这里就简单跟着官方教程做了下练习 参考文档:https://v1-27.docs.kubernetes.io/zh-cn/docs/tutorials/hello-minikube/ 这里最重要的是,你需要提前配置好你的网络。 这个我教不了,之前发了篇帖子vmware实现科学上网审核不通过&…

ElasticSearch 全文检索相关性 算分

文章目录 相关性相关性Relevance相关性算法TF-IDFBM25 通过Explain查看TF-IDFboosting query 多字段查询 相关性dis_max query最佳字段查询multi_match querybest_fields最佳匹配字段most_fields 多数字段搜索cross_fields跨字段搜索 相关性 相关性Relevance 搜索的相关性算分…

Ubuntu 通过 docker 安装 Nginx 镜像 + 创建并运行 nginx01 容器

一、安装 nginx:精简版镜像 1. 查找有什么类型的 nginx 镜像 yammiemy-pc >/home/yammie $ docker search nginx 2. 下载精简版 nginx 镜像 yammiemy-pc >/opt $ docker pull nginx:alpine alpine: Pulling from library/nginx 46b060cc2620: Already exists 21af147…

【深度学习|目标跟踪】快速入门卡尔曼滤波!

卡尔曼滤波详解 申明一、什么是卡尔曼滤波1.1 卡尔曼滤波的使用场景1.2 卡尔曼滤波的定义 二、卡尔曼滤波公式详解(无推导)三、卡尔曼滤波的简单应用 申明 本博客参考了b站up主“华南小虎队”的卡尔曼滤波教学视频以及Lauszus Kristian Sloth Lauszus的卡…

联想Thinkpad驱动安装下载(官网的驱动下载)

联想Thinkpad驱动安装官网下载地址: 联想驱动管理_ThinkPad服务网站-联想服务 联想驱动管理 帮助您更快速准确的定位驱动 自动下载安装,安装驱动不求人 软件版本:V2.9.0719.1104 | 大小:5.7M最后更新:2021-07-21支持系统&#…

41.【C语言之外】聊聊Cheat Engine官方教程步骤6的思考

0.看前须知 有一定指针概念的基础 推荐阅读前几篇博文: 19.【C语言】指针(重难点)(A) 37.【C语言】指针(重难点)(B) 38.【C语言】指针(重难点&#xff09…

oracle的exp.exe、imp.exe在哪下载?

需要oracle账号 地址: Instant Client for Microsoft Windows (x64) 64-bit 下载这个工具包

开发一个能打造虚拟带货直播间的工具!

在当今数字化时代,直播带货已成为电商领域的一股强劲力量,其直观、互动性强的特点极大地提升了消费者的购物体验。 然而,随着技术的不断进步,传统直播带货模式正逐步向更加智能化、虚拟化的方向演进,本文将深入探讨如…

智慧景区系统开发功能定制

智慧景区系统开发功能定制是一项综合性服务,它涉及到利用云计算、物联网、AI监控等先进技术,通过互联网和移动互联网,实现景区智慧化管理和服务提升。 以下是智慧景区系统开发中应考虑的关键功能点: 游客服务平台:包…

23款奔驰E350eL升级原厂香氛负离子系统,保持一股高级的香味

相信大家都知道,奔驰自从研发出香氛负离子系统后,一直都受广大奔驰车主的追捧,香氛负离子不仅可以散发出清香淡雅的香气外,还可以对车内的空气进行过滤,使车内的有害气味通过负离子进行过滤,达到车内保持清…

“AI能不能代替某某职业”,到底谁在破防?

前几天,公司在午间分享时谈到一个有趣的辩题:“AI能不能代替产品经理”,不仅双方辩手打了个你来我往,就连下面的吃瓜群众也进入红温状态。 “AI能不能代替xx”已经成为一个普遍的话题,在某乎上随手一刷就是不同的职业…

Linux 利用 ftrace 分析内核调用

目录 一、概述二、ftrace 的使用1、常用信息2、指定 ftrace 跟踪器3、设置要跟踪的函数4、ftrace 的开关5、function 跟踪程序6、function_graph 跟踪程序7、函数过滤器8、跟踪事件 三、trace-cmd 的使用1、常见命令2、常用选项2.1 列出可用的追踪器2.2 跟踪特定进程的函数调用…

如何用剪映自动批量生成左右分屏的视频?

做tiktok中视频计划的朋友,应该都知道一种批量做号的模式,就是找一些热门视频作为左边主机视频,右边则放上一些减压类视频以保存画面的原创度,像下面这种。 这种视频是如何批量用剪映生成的呢? 一、准备好素材 下载好…

数据结构——栈的讲解(超详细)

前言: 小编已经在前面讲完了链表和顺序表的内容,下面我们继续乘胜追击,开始另一个数据结构:栈的详解,下面跟上小编的脚步,开启今天的学习之路! 目录 1.栈的概念和结构 1.1.栈的概念 1.2.栈的结构…

redis面试(十五)公平锁队列重排

队列重拍 先说一下当前的加锁状态 anyLock由客户端A持有队列中是客户端B、客户端C并且客户端B现在是排在头部 那么队列重拍就是队列中某个客户端长时间没有重新申请加锁,没有刷新分数,就会被队列中挤掉。 假设这个长时间没有加锁的客户端是B。 总结 …