Android入门第41天-Android中的Service(bindService)

news2024/9/21 2:44:40

介绍

在前一天我们介绍了Android中有两种启动Service的方法。并擅述了startService和bindService的区别。同时我们着重讲了startService。

因此今天我们就来讲bindService。bindService大家可以认为它是和Android的一个共生体。即这个service所属的activity如果消亡那么bindService也会消亡。

因此今天我们以一个比较复杂的例子,activity<->service间互相传值来讲透这个bindService的使用,同时我们在这个例子中故意留下一个坑即:在Service里使用Thread处理大事务是不是就一定安全呢?也不安全,它也会引起ANR即:Application Not Responding-安卓崩溃。从而以这个坑来引出IntentService的使用。

来看例子

我们设有三个按钮:

  • 【BIND SERVICE】-点击后运行Service
  • 【STOP BINDING】-点击后结束Service
  • 【GET VALUE FROM BINDER】-通过Activity获取正在BINDING的Service内的值,此处我们留下了一个ANR的坑,即获取Service内的值时我们留了一个Thread.Sleep(30000)的长事务,来观察ANR;

此处记得按钮的点击顺序为:先点【BIND SERVICE】->再点【GET VALUE FROM BINDER】->再点【STOP BINDING】不过此处你没有机会点这个【STOP BINDING】按钮,因为在GET时你已经ANR(崩溃)了。

来看全代码展示。

全代码

Service注册

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DemoBindService"
        tools:targetApi="31">
        <service
            android:name=".SampleBindService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action
                    android:name="org.mk.android.demo.SampleBindService"/>
            </intent-filter>

        </service>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

 Service类(坑来了)

package org.mk.android.demo;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class SampleBindService extends Service {
    private final String TAG = "SimpleBindService";
    private int count;
    private boolean quit;
    private CountNumBinder countNumBinder = new CountNumBinder();

    public SampleBindService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        Log.i(TAG, ">>>>>>onBind方法被调用");
        return countNumBinder;
    }

    //Service被关闭前回调
    @Override
    public void onDestroy() {
        super.onDestroy();
        this.quit = true;
        Log.i(TAG, ">>>>>>onDestroyed方法被调用!");
    }

    @Override
    public void onRebind(Intent intent) {
        Log.i(TAG, ">>>>>>onRebind方法被调用!");
        super.onRebind(intent);
    }

    //Service被创建时调用
    @Override
    public void onCreate() {
        Log.i(TAG, ">>>>>>onCreate方法被调用");
        super.onCreate();
        //创建一个线程动态地修改count的值
        new Thread() {
            public void run() {
                while (!quit) {
                    try {
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }

            ;
        }.start();
    }

    //Service断开连接时回调
    @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, ">>>>>>onUnbind方法被调用!");
        return true;
    }

    //Service被启动时调用
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, ">>>>>>onStartCommand方法被调用");
        return super.onStartCommand(intent, flags, startId);
    }


    public class CountNumBinder extends Binder {
        public int getCount() {
            Log.i(TAG, ">>>>>>into long waiting");

            try {
                Thread.sleep(300000);
            } catch (Exception e) {
            }

            return -1;
        }
    }
}

我们可以看到,这个Service以每秒对着count+1.

然后通过bindService的onBind生命体里以一个CountNumBinder暴露出去,给到外部可以通过一个getCount方法来调用获取Service里当前count的值,但是这个值在获取前我们会使用Thread.sleep(30000)-30秒来模拟ANR。

主运行类-MainActivity.java

  • 在调用Service的activity里我们使用bindService(intent, conn, Service.BIND_AUTO_CREATE);来启动。
  • 这边这个conn是一个ServiceConnection类,new出一个ServiceConnection类并覆盖里面的
    • onServiceConnected方法,用于接受bindService返回的对象;
    • onServiceDisconnected方法,用于在这个bindService被销毁时作处理;

具体代码如下:

package org.mk.android.demo;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private final String TAG = "SimpleBindService";
    private Button buttonBindService;
    private Button buttonStopBinding;
    private Button buttonGetValueFromBinder;
    private Context ctx;
    private Intent intent;
    private SampleBindService.CountNumBinder countNumBinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonBindService = (Button) findViewById(R.id.buttonBindService);
        buttonStopBinding = (Button) findViewById(R.id.buttonStopBinding);
        buttonGetValueFromBinder = (Button) findViewById(R.id.buttonGetValueFromBinder);
        ctx = MainActivity.this;
        intent = new Intent(ctx, SampleBindService.class);
        buttonBindService.setOnClickListener(new OnClickListener());
        buttonStopBinding.setOnClickListener(new OnClickListener());
        buttonGetValueFromBinder.setOnClickListener(new OnClickListener());
    }

    private ServiceConnection conn = new ServiceConnection() {

        //Activity与Service断开连接时回调该方法
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, ">>>>>>Service DisConnected");
        }

        //Activity与Service连接成功时回调该方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, ">>>>>>Service Connected");
            countNumBinder = (SampleBindService.CountNumBinder) service;
        }
    };

    class OnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            Intent eIntent;
            switch (view.getId()) {
                case R.id.buttonBindService:
                    bindService(intent, conn, Service.BIND_AUTO_CREATE);
                    break;
                case R.id.buttonStopBinding:
                    unbindService(conn);
                    break;
                case R.id.buttonGetValueFromBinder:
                    Toast.makeText(getApplicationContext(), "Service的count" + "的值为:" + countNumBinder.getCount(), Toast.LENGTH_LONG).show();
                    break;
            }
        }
    }
}

运行效果

  1. 先点【BIND SERVICE】;
  2. 再点【GET VALUE FROM BINDER】;

看,ANR出现了。

这就是我说的坑,怎么解决这个坑,请听下回分解。

 

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

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

相关文章

Docker涉及的Linux命名空间、CGroups

概述 Linux的NameSpace介绍 很多编程语言都包含了命名空间的概念&#xff0c;我们可以认为命名空间是一种封装&#xff0c;封装本身实现了代码的隔离。在操作系统中命名空间提供的是系统资源的隔离&#xff0c;其中系统资源包括了&#xff1a;进程、网络、文件系统…实际上li…

《模拟电子技术》半导体原理部分笔记

《模拟电子技术》笔记绪论第一章 常用半导体器件第二章 基本放大电路绪论 有的人把三极管的出现作为电子技术工业革命的开始标志学习架构&#xff1a;半导体器件&#xff08;二极管、三极管、场效应晶体管&#xff09;、基于上述管的放大电路、集成运算放大器、放大电路的频率…

第11章 初识IdentityServer4

1 构建IdentityServer4 服务 1.1 通过配置类配置类(Config)实例化IdentityServer4中间件 using IdentityServer4.Models; namespace BuilderServer { /// <summary> /// 【配置--类】 /// <remarks> /// 摘要&#xff1a; /// 通过该中类的方法成员&#xff…

如何给firefox和google chrome鼠标手势

背景 已经习惯了有鼠标手势&#xff0c;因为一天到晚都在浏览器上查询资料&#xff0c;所以必须把这个鼠标手势设置好。 firefox 搜索Foxy Gestures然后安装 google chrome crxMouse Chrome 点击google浏览器上的扩展程序图标&#xff0c;然后点击管理扩展程序&#xff1a…

游泳耳机哪个牌子好、分享几款游泳听音乐最好的耳机推荐

如今,水上运动爱好者越来越多了,无论是游泳,还是冲浪早已成为了我们很多人经常参加的运动项目。不过他们都抱怨过类似的问题——可以在水上运动中使用的无线耳机实在是太少了。防水性能达不到可游泳级别,不带内存需要配备手机使用,这些都是造成耳机无法在水上使用的原因。今天小…

【matplotlib】1-使用函数绘制图表

文章目录使用函数绘制图表1.绘制matplotlib图表组成元素的主要函数2.准备数据3.函数用法3.1函数plot()--展现变量的趋势变化3.2函数scatter()--寻找变量之间的关系3.3函数xlim()--设置x轴的数值显示范围3.4函数xlabel()--设置x轴的标签文本3.5 函数grid()--绘制刻度线的网格线3…

Kong(三)Konga UI安装和使用

一 konga 的github地址 konga安装参考 ① Kong 可视化UI 选择 官方kong-dashboard 1&#xff09;收费&#xff1a;当前kong的社区版是没有dashboard的,但是付费的企业版是有带的2&#xff09;kong-dashboard最新版本v3.6.0,只支持到kongv0.14.x,对于更高的kong版本,功能支…

SpringBoot整合RabbitMQ,实现单机抢票系统

MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法。MQ是消费-生产者模型的一个典型的代表&#xff0c;一端往消息队列中不断写入消息&#xff0c;而另一端则可以读取队列中的消息。 消息中间件最主要的作用是解耦&#xff0c;中间…

C与C++中的常用符号与标点用法详解及实例

C与C中的常用符号与标点符号有&#xff1a;“”、“-”、“*”、 “/”、“%”、“&”、“\”、“|”、“~”、“^”、“&”、“|”、“&#xff01;”、“>”、“<”、""、“#”、“&#xff1f;”、“&#xff0c;”、“.”、“&#xff1a;”、单引…

d3rlpy离线强化学习算法库安装及使用

GitHub - takuseno/d3rlpy: An offline deep reinforcement learning library d3rlpy&#xff0c;离线强化学习算法库 我装在windows下用anaconda&#xff0c;按照官网教程 conda install -c conda-forge d3rlpy 第一次安装报错CondaSSLError: OpenSSL appears to be unavaila…

Kubernetes的service详解

文章目录Service介绍Service类型Service使用ClusterIP类型的ServiceHeadLiness类型的ServiceNodePort类型的ServiceLoadBalancer类型的ServiceExternalName类型的ServiceIngress介绍Service介绍 在kubernetes中&#xff0c;pod是应用程序的载体&#xff0c;我们可以通过pod的i…

程序人生 | 与足球共舞的火柴人(致敬格拉利什,赋予足球更深的意义)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿多个前端 offer&#xff08;秋招&#xff09; &#x1f680;未…

从0开始学游戏开发

对于开发而言&#xff0c;了解一下如何从零开始做游戏是一个非常有趣且有益的过程(并不)。这里我先以大家对游戏开发一无所知作为前提&#xff0c;以一个简单的游戏开发作为.从0开始学游戏开发。 写在最前面 对于开发而言&#xff0c;了解一下如何从零开始做游戏是一个非常有趣…

Twice-JavaSE01

狂神学习路线&#xff1a; 今天又重头开始复习Java了&#xff0c;不顾一切往前冲吧。 空常量null不能直接输出。其他几种基本数据类型可以直接输出。 定义变量时要给赋值才行&#xff0c;浮点型默认为double,float类型后要加f. 注意&#xff1a;byte和short不能直接跟char做…

【强化学习论文合集 | 2019年合集】一. ICML-2019 强化学习论文

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

C++-容器:string使用介绍(非常全面,详细)

string的初始化 1.常见初始化方式 string对象的初始化和普通类型变量的初始化基本相同&#xff0c;只是string作为类&#xff0c;还有类的一些特性&#xff1a;使用构造函数初始化。如下表&#xff0c;第2 4 6条是作为类才有的初始化方式&#xff1a; 当然&#xff0c;也可以…

MySQL数据库之事务

MySQL数据库之事务一、事务的概念二、事务的ACID特点2.1 原子性&#xff08;保证事务的整体性&#xff09;2.2 一致性&#xff08;保证数据的完整性&#xff09;2.3 隔离性2.4 持久性三、事务控制语句3.1 测试begin和commit&#xff08;开始事务和提交事务&#xff09;begin开启…

毕业设计-基于机器视觉的车型识别系统

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

【人脸识别】Octuplet Loss:一个可以提高低分辨率和跨分辨率人脸识别效果的损失

论文题目&#xff1a;《Octuplet Loss:Make Face Recognition Robust to Image Resolution》 论文地址&#xff1a;https://arxiv.org/pdf/2207.06726v1.pdf 代码地址&#xff1a;https://github.com/martlgap/octuplet-loss 1.概述 一般来说&#xff0c;在图像分辨率方面&…

多线程设计模式-全面详解(学习总结---从入门到深化)

目录 Single Thread Execution 设计模式 机场过安检 非线程安全 问题分析 首字母相同却未通过检查 为何出现首字母不相同的情况 线程安全 Future 设计模 Master-Worker 设计模式 生产者消费者设计模式 Immutable 不可变对象设计模式 关于时间日期 API 线程不安全的问题…