Android复习(Android基础-四大组件)——Service与Activity通信

news2024/12/22 6:32:14
  • 我们前面学会了启动和停止服务的方法,但是服务虽然是在活动里启动的,但是启动服务之后,活动与服务之间基本没什么关系了。
  • 正常情况,我们在Activity里调用startService()方法启动MyService这个服务,然后MyService的onCreate()和onStartCommand()方法就会得到执行。之后服务会一直处于运行状态,具体运行什么逻辑,活动控制不了
  • 如果我们想让活动和服务的关系更紧密一些。例如在活动中指挥服务去干什么,服务就去干什么。就要使用我们刚刚忽略的onBind()方法

1. 绑定服务

1.1 绑定服务的流程

  • 下面举一个例子:我们希望在MyService里实现一个下载功能,然后在Activity可以决定何时开始下载,以及随时查看下载的进度。
  • 我们可以专门创建一个Binder对象来对下载功能进行管理。
public class MyService extends Service {
    public MyService() {
    }
    
    class DownloadBinder extends Binder{
        public void startDownload(){
            Log.d("MyService", "startDownload executed");
        }
        public void getProgress(){
            Log.d("MyService", "getProgress execute");
        }
    }
    //一个Binder对象来对下载功能进行管理
    private DownloadBinder mBinder = new DownloadBinder();


    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}
  • MainActivity中创建连接,调用bindService进行服务和Activity之间的绑定。
public class MainActivity extends AppCompatActivity {
    //1.获取Binder
    private MyService.DownloadBinder downloadBinder;
    //2.获取connection
    private ServiceConnection connection = new ServiceConnection() {
        //这两个方法会在活动与服务成功绑定以及解除绑定前后调用
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //向下转型获得mBinder
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this , MyService.class);
        bindService(intent , connection , BIND_AUTO_CREATE);
        unbindService(connection);
    }
}

1.2 绑定服务的相关知识点

  • IBinder

    1. 可以将多个客户端同时连接到某项Service。
    2. 系统会缓存IBinder服务通信通道。当第一个客户端绑定Service时,系统会调用onBind()方法生成IBinder。系统会将该IBinder传递给其他所有客户端(绑定了当前Service的)。无需再次调用onBind()
    3. 当最后一个客户端取消与Service的绑定时,系统会销毁该Service(除非还通过startService启动了当前Service)
  • bindService()

    1. bindService()的返回值指示所请求的Service是否存在,以及是否允许客户端访问该Service。
    2. 返回false,说明客户端与Service之间并无有效连接。不过,客户端仍然需要调用unbindService()。否则客户端会使Service无法在空闲时关闭。
  • Intent(第一个参数)

    1. 第一个参数是Intent,用来显示命名要绑定的Service。
    2. 隐式Intent启动Service存在安全隐患,让用户无法确定哪些服务器启动了。所以在Android5.0开始使用隐式Intent调用bindService()系统会抛出异常
  • ServiceConnection(第二个参数)

    1. 必须提供ServiceConnection的实现,用于监控与Service的连接。
    2. Android系统创建客户端与Service之间的连接时,会对ServiceConnection调用onServiceConnected()。onServiceConnected方法包含一个IBinder参数,客户端随后会使用该参数与绑定Service通信
  • 绑定选项的标记(第三个参数)

    1. 如果要创建尚未处于活动状态的Service,此参数通常为BIND_AUTO_CREATE。
    2. 其他可能的值为BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,或者0(表示无参数)

2. Service与Activity之间的通信

  1. 通过Binder进行通信
  2. 通过BroadCast
  3. 通过Messenger

2.1 Binder

  • 在Service中拓展Binder类,并从onBind()返回该类的实例。
  • 客户端收到Binder后,可以利用它直接访问 Binder实现 或 Service中提供的公共方法。

具体流程(代码见1.1)
1. 在Service中自定义一个Binder类,并创建可执行以下某种操作的Binder实例:

  • 包含Activity客户端可以调用的 public方法。
  • 返回当前的Service实例,该实例中包含客户端可调用的公共方法。
  • 返回由Service承载的其他类的实例,其中包含客户端可调用的公共方法。

2.从onBind()方法返回此Binder实例
3. 在客户端中,在ServiceConnection的onServiceConnected()回调方法中接收Binder,并使用提供的方法调用绑定Service。

  • 这样我们就可以通过这个Binder对象去调用我们定义的方法去控制Service。

代码2

  • LocalService(返回的是Service的实例,实例中包含客户端可以调用的方法getRandomNumber)
public class LocalService extends Service {
    private final IBinder binder = new LocalBinder();
    private final Random mGenerator = new Random();

    public class LocalBinder extends Binder {
        LocalService getService() {
            return LocalService.this;
        }
    }

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


    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}
  • BindingActivity
public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // 绑定服务
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        //解绑服务
        unbindService(connection);
        mBound = false;
    }

    public void onButtonClick(View v) {
        if (mBound) {
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    
    //连接,监听Service
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className , IBinder service) {
            //向下转型获取Binder
            //获取Service
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

2.2 Broadcast

  • 发送广播也可以实现Service和Activity的通信
  • 在服务里面发送广播
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("Ning", "onStartCommand: ");
    Intent newIntent = new Intent();
    newIntent.putExtra("key" , "text");
    newIntent.setAction("location.report");
    sendBroadcast(newIntent);
    return super.onStartCommand(intent, flags, startId);
}
  • MainActivity中创建广播接收器
//内部类,实现BroadcastReceiver,创建内部类作为广播接收器
public class LocationReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if(intentAction.equals("location.report")){
            Log.d("Ning", "onReceive: 111111111");
        }
    }
}
  • onCreate注册广播和onDestroy注销广播
    LocationReceiver locationReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        locationReceiver = new LocationReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("location.report");
        registerReceiver(locationReceiver , intentFilter);
        Log.d("Ning", "onReceive: 11111");

        Intent intent = new Intent(this , MyService.class);
        startService(intent);
    }
    
    @Override
    protected void onDestroy() {
        unregisterReceiver(locationReceiver);
        super.onDestroy();
    }

2.3 使用Messenger

  • 如需让接口跨不同进程工作,可以使用Messenger为Service提供接口。
    • 这种方式,Service会绑定一个Handler,用于响应不同类型的Message对象。在Service中创建一个Messenger对象并绑定Handler,重写handler的handleMessage。
  • Messenger是执行进程间通信(IPC)最为简单的方式,因为Messenger会在单个线程中创建包含所有请求的队列,这样就不必对Service进行线程安全设计。
    在这里插入图片描述
public class MessengerService extends Service {
    
    static final int MSG_SAY_HELLO = 1;
    
    //1.实现IncomingHandler来接收客户端的每个回调
    static class IncomingHandler extends Handler{
        private Context applicationContext;
        
        IncomingHandler(Context context){
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    
    Messenger mMessenger;
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        //2.使用Handler创建Messenger对象,
        mMessenger = new Messenger(new IncomingHandler(this));
        //3.Messenger创建一个IBinder
        return mMessenger.getBinder();
    }
}
  • 接下来,Service会在Handler的handleMessage()方法中接收传入的Message,并根据what决定下一步操作。
  • 客户端只需根据Service返回的IBinder创建Messenger,使用send()发送消息。
public class ActivityMessenger extends Activity {
    Messenger mService = null;
    boolean bound;

    //连接
    //这里用和服务端一样的IBinder创建一个Messenger
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            bound = false;
        }
    };


    //通过这个Messenger发送Message
    public void sayHello(View v) {
        if (!bound) return;
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
}

3. 相关问题

3.1 Service中更新UI?

在这里插入图片描述

3.2 如何保证Service不被杀死?

在这里插入图片描述

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

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

相关文章

Openlayers实战:利用turf获取两个多边形的交集、差集、并集

在数据统计方面,通常会涉及到图形间的交集、并集、差集等。在Openlayers的实战中,我们显示两个多边形的交集、并集、差集的表现。通过turf的方式,可以快速的实现我们的数据处理,具体的请参考源代码。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师…

three.js的镜面反射

three.js做成这种镜面反射的效果。 那就要使用three自带的功能Reflector 1.引入 组件 import { Reflector } from ../../node_modules/three/examples/jsm/objects/Reflector.js; 2.创建反射投影的存在面 let reflectorGeometry new THREE.PlaneBufferGeometry(100, 100); 3…

Java经典面试题总结(一)

Java经典面试题总结(一) 题一:Java编译运行原理题二:JDK,JVM,JRE三者之间的关系题三:谈一下对冯诺依曼体系的了解题四:重载与重写的区别题五:拆箱装箱是指什么&#xff1…

Spring源码解析(八):bean后置处理器CommonAnnotationBeanPostProcessor

Spring源码系列文章 Spring源码解析(一):环境搭建 Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean Spring源码解析(三):bean容器的刷新 Spring源码解析(四):单例bean的创建流程 Spring源码解析(五)&…

本地项目如何连接git远程仓库

在本地新建项目后,如何连接git远程仓库呢?步骤如下: 第一步, 首先我们在git上新建仓库,设置模板可勾选Readme文件。(readme文件的创建是为了介绍所写代码的一些详细信息,为了之后更好的维护。)…

记录问题: servlet获取项目包绝对路径

【2023-8-8 23:46:27 星期二】 如何获取在webapp下的路径?而不是target包下的webapp目录 比如这里应该获取到 F:\Tiam\Desktop\freemarker\freemarker-demo01\src\main\webapp 而readPath总是获取到 F:\Tiam\Desktop\freemarker\freemarker-demo01\target\freemarker-demo0…

Leetcode-每日一题【剑指 Offer 11. 旋转数组的最小数字】

题目 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4…

Styletron: 面向组件的样式设计工具包

styletron官网: styletron的GitHub链接: styletron-react 一. 介绍 Styletron是一个通用的component-oriented(面向组件的)样式工具。它属于css-in-js类别。Styletron可以很好地与React配合使用,但也可以与其他框架或…

Allegro172版本无法低亮颜色的解决办法

Allegro172版本无法低亮颜色的解决办法 在用Allegro172版本做PCB设计的时候,高亮颜色是常用的命令,同时将高亮的颜色去高亮也是使用的十分频繁。 有时在去高亮的时候会出现无法去高亮的情况如下图 右边这块铜皮被高亮成了白色 可以看到即便使用去高亮命令,铜皮的颜色仍然还…

初次使用GPU云服务器

前言: 在体验了GPU云服务器(GPU Cloud Computing,GPU)后,我认为这是一个非常强大的弹性计算服务。它为深度学习、科学计算、图形可视化、视频处理等多种应用场景提供了强大的GPU算力,能够满足各类用户的计算…

web集群学习--基于CentOS构建LVS-DR集群、配置nginx负载均衡

基于CentOS构建LVS-DR集群 环境准备 主机名 ip地址 node1 192.168.1.140 client node2 192.168.1.141 LVS node3 192.168.1.142 RS1 node4 192.168.1.143 RS2配置 1.关闭防火墙和SELinux [rootclient~]# systemctl stop firewalld [rootclient~]# systemctl disabl…

实现UDP可靠性传输

文章目录 1、TCP协议介绍1.1、ARQ协议1.2、停等式1.3、回退n帧1.4、选择性重传 1、TCP协议介绍 TCP协议是基于IP协议,面向连接,可靠基于字节流的传输层协议 1、基于IP协议:TCP协议是基于IP协议之上传输的,TCP协议报文中的源端口IP…

【Linux升级之路】5_基础IO

🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux升级之路】 ✒️✒️本篇内容:文件操作,文件管理,重定向,简易shell添加重定向功能,文件属…

领航优配:暑期旅游市场热度持续攀升,相关公司业绩有望持续释放

到发稿,海看股份涨停,中广天择、探路者、众信旅行等涨幅居前。 8月8日,在线旅行板块震动上涨,到发稿,海看股份涨停,中广天择、探路者、众信旅行等涨幅居前。 今年以来,国内旅行商场逐渐恢复。文…

Unity制作护盾——2、力场冲击波护盾

Unity制作力场护盾 大家好,我是阿赵。   继续做护盾,这一期做一个力场冲击波护盾。 一、效果展示 主要的效果并不是这个球,而是护盾在被攻击的时候,会出现一个扩散的冲击波。比如上图在右边出现了冲击波 如果在左边被攻击&am…

安装ubuntu 18.04 系统(1)——制作系统安装U盘

https://rufus.ie/zh/ 下载该软件,准备制作启动盘下载自己想要的镜像,http://mirrors.163.com/ubuntu-releases/18.04/, 我选择的是ubuntu-18.04.6-live-server-amd64.iso 因为,科研写程序使用,不需要桌面版本。开始制…

分布式协议与算法——拜占庭将军问题

拜占庭将军问题 背景:以战国时期为背景 战国时期,齐、楚、燕、韩、赵、魏、秦七雄并立,后来秦国的势力不断强大起来,成了东方六国的共同威胁。于是,这六个国家决定联合,全力抗秦,免得被秦国各个…

go错误集(持续更新)

1.提示以下报错 Build Error: go build -o c:\Users\Administrator\Desktop__debug_bin2343731882.exe -gcflags all-N -l . go: go.mod file not found in current directory or any parent directory; see ‘go help modules’ (exit status 1) 解决办法: go …

mysql进阶篇(二)

前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 「推荐专栏」: ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄,vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

知识贴:如何使用校对软件改善新闻稿件的质量

使用校对软件改善新闻稿件的质量可以按照以下步骤进行: 1.选择适合的校对软件:市场上有许多校对软件可供选择,例如语法和拼写检查工具,自动校对工具以及专门为新闻写作而设计的工具。根据自己的需求和预算,选择最适合的…