学习Android的第二十九天

2024-03-15 15:04
文章标签 android 学习 第二十九

本文主要是介绍学习Android的第二十九天,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

Android Service 与 Activity 通讯

范例

Android Service Alarm 定时广播

Alarm

Alarm 使用流程

范例

Android IBinder

Binder

为什么是 Binder ?


Android Service 与 Activity 通讯

Activity 与 Service 通信的媒介就是 Service 中的 onBind() 方法,onBind() 方法会返回一个自定义的 Binder 对象。

  1. 在自定义的 Service 类中,我们会创建一个继承自 Binder 的自定义 Binder 类,其中包含了我们想要暴露给 Activity 的方法。这个 Binder 类负责实现跨进程通信所需的接口。
  2. 在 Service 类中,我们需要实例化这个自定义的 Binder 类,并且在 onBind() 方法中返回这个 Binder 对象。
  3. 在 Activity 类中,我们需要实例化一个 ServiceConnection 对象,并且重写 onServiceConnected() 方法。当连接到 Service 时,系统会调用 onServiceConnected() 方法,并提供一个 Binder 对象,通过它可以调用 Service 中暴露的方法。

范例

package com.example.myapplication2;import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;public class MyService extends Service {public void doSomething() {}// 自定义的 Binder 类public class MyBinder extends Binder {MyService getService() {return MyService.this;}// 暴露给 Activity 的方法public void doSomething() {// 在这里执行具体的操作}}private final IBinder mBinder = new MyBinder();@Overridepublic IBinder onBind(Intent intent) {return mBinder;}
}
package com.example.myapplication2;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 androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private MyService mService;private boolean mBound = false;// ServiceConnection 对象private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {MyService.MyBinder binder = (MyService.MyBinder) service;mService = binder.getService();mBound = true;// 在这里可以调用 Service 中暴露的方法mService.doSomething();}@Overridepublic void onServiceDisconnected(ComponentName arg0) {mBound = false;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 启动 ServiceIntent intent = new Intent(this, MyService.class);startService(intent);}@Overrideprotected void onStart() {super.onStart();// 绑定到 ServiceIntent intent = new Intent(this, MyService.class);bindService(intent, mConnection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();// 解绑 Serviceif (mBound) {unbindService(mConnection);mBound = false;}}
}

Android Service Alarm 定时广播

对于在 Android 应用中执行定时任务,特别是需要长期在后台运行的定时任务,使用 Alarm 机制是更为可靠和适合的选择。相比之下,Timer 类存在一些局限性,如在设备休眠时无法保证准确执行定时任务。

Alarm 机制通过设置系统级别的闹钟来触发某个操作,即使应用处于后台或设备休眠状态,也能够唤醒 CPU 并执行相应的任务。这种方式适合于需要长期在后台持续执行的定时任务,比如轮询服务器进行数据更新或状态确认等。

同时,在使用 Alarm 机制时,需要注意区分 CPU 唤醒与屏幕唤醒。CPU 唤醒是指在设备休眠状态下唤醒 CPU 执行任务,而屏幕唤醒则是指设备从休眠状态恢复到亮屏状态。通常情况下,我们希望定时任务能够唤醒 CPU 执行而不会唤醒屏幕,以节省设备电量并保持用户体验。

总的来说,针对需要长期在后台执行的定时任务,推荐使用 Alarm 机制,它可以可靠地唤醒 CPU 执行任务,且能够有效管理定时任务的触发和执行。

Alarm

对于 Android 中 AlarmManager 的 set() 方法,参数包括类型(type)、开始时间(startTime)和 PendingIntent 对象(pi),这些参数决定了闹钟的执行方式和动作。

1. 类型(type):

  1. AlarmManager.ELAPSED_REALTIME:相对于系统启动时间的相对时间,手机睡眠时不可用。
  2. AlarmManager.ELAPSED_REALTIME_WAKEUP:相对于系统启动时间的相对时间,手机睡眠时会唤醒系统。
  3. AlarmManager.RTC_WAKEUP:绝对时间,手机睡眠时会唤醒系统。
  4. AlarmManager.POWER_OFF_WAKEUP:在手机关机状态下也能正常提示功能,但受SDK版本影响,可能并不是所有版本都支持。

   
2. 开始时间(startTime):

  • 决定了闹钟的第一次执行时间,以毫秒为单位。可以使用 SystemClock.elapsedRealtime() 或 System.currentTimeMillis() 根据类型来获取合适的时间。 

3. PendingIntent 对象(pi):

用于绑定闹钟的执行动作,比如发送广播、给出提示等等。

  • 如果通过启动服务来实现闹钟提示,应该使用 `Pending.getService()` 方法获取 PendingIntent 对象。
  • 如果通过广播来实现闹钟提示,应该使用 `PendingIntent.getBroadcast()` 方法获取 PendingIntent 对象。
  • 如果通过 Activity 来实现闹钟提示,应该使用 `PendingIntent.getActivity()` 方法获取 PendingIntent 对象。

正确选择 PendingIntent 获取方法很重要,否则虽然不会报错,但可能无法看到闹钟提示效果。根据实际情况选择合适的 PendingIntent 获取方法,确保闹钟的执行动作能够按预期进行。

Alarm 使用流程

使用 Alarm 的一般流程如下:

1、获取 AlarmManager 对象:

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

2、使用 set() 方法设置定时任务:

int durtime = 2 * 1000; // 单位毫秒
long triggerAtTime = SystemClock.elapsedRealtime() + durtime;
manager.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pendingIntent);

3、定义一个 Service,在其 onStartCommand() 方法中开辟一条事务线程,用于处理定时逻辑。

4、定义一个广播(Broadcast),用于启动 Service。

5、在 AndroidManifest.xml 文件中注册 Service 和 Broadcast。

请注意,对于 Android 4.4+(API 19)的设备,Alarm 任务的触发时间可能会变得不准确,有可能会有延时。这是系统为了进行耗电性的优化所做的调整。如果需要准确无误的触发时间,可以考虑使用 setExact() 方法。

范例

1、创建一个新的 Java 类,命名为 AlarmReceiver,继承自 BroadcastReceiver:

package com.example.myapplication2;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;public class AlarmReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "定时任务触发", Toast.LENGTH_SHORT).show();}
}

2、在 AndroidManifest.xml 文件中注册 AlarmReceiver 广播:

<receiver android:name=".AlarmReceiver" />

3、修改MainActivity.java:

package com.example.myapplication2;import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent = new Intent(this, AlarmReceiver.class);PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);long triggerAtTime = SystemClock.elapsedRealtime() + 5000; // 5秒后触发alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);}
}

Android IBinder

IBinder是Android系统中用于远程对象通信的关键接口之一。以下是您提供的内容的总结:

IBinder的作用:

  • IBinder是远程对象的基本接口,用于高性能的轻量级远程调用机制。

IBinder的使用:

  • 不仅用于远程调用,也可用于进程内调用。
  • 一般情况下,我们通过继承Binder类来实现IBinder接口,而不是直接实现该接口。

主要方法:

  • transact():向远程IBinder对象发送调用。
  • onTransact():响应接收到的调用。
  • 这些方法是同步执行的,比如transact()在对方的onTransact()方法调用完成之前不会返回。

数据传输:

  • transact()发送的数据是通过Parcel进行传输的。
  • Parcel是一种通用的缓冲区,除了数据外,还包含描述其内容的元数据。
  • 元数据用于管理IBinder对象的引用,以便在进程间移动Parcel时保存这些引用。

进程间通信:

1、IBinder和Binder之间的管理类似于唯一标识符。
2、在操作远程对象时,可能需要确保它们是有效的。可以使用以下方法:

  • 当目标进程不存在时,使用transact()方法会抛出RemoteException异常。
  • 调用pingBinder()时,如果目标进程不存在,则返回false。
  • 可以使用linkToDeath()方法向IBinder注册一个IBinder.DeathRecipient,在代表的进程退出时调用。

Binder

在 Binder 机制中,通常存在以下组件和调用流程:

Client(客户端):

  • 客户端是使用 Binder 机制进行远程调用的应用程序或组件。
  • 客户端通过获取服务的代理对象(Proxy)来调用远程服务的方法。
  • 客户端通过 Binder 机制将请求发送到服务端。

Server(服务端):

  • 服务端是提供远程服务的应用程序或组件。
  • 服务端通过实现具体的业务逻辑来响应客户端的请求。
  • 服务端通过 Binder 机制接收来自客户端的请求,并执行相应的操作。

Service Manager(服务管理器):

  • 服务管理器是 Android 系统中的一个系统服务,负责维护 Binder 对象的注册表。
  • 它允许客户端通过 Binder 对象的名称来查找远程服务,并获取其代理对象。

Binder 驱动程序:

  • Binder 驱动程序是 Android 系统中的内核模块,负责处理 Binder 通信的底层细节。
  • 它负责跟踪 Binder 对象的生命周期、实现进程间通信和线程间通信的机制。

Binder 机制的调用流程如下:

  1. 客户端通过 Service Manager 获取远程服务的代理对象(Proxy)。
  2. 客户端调用代理对象的方法,传递参数和回调接口(如果需要)。
  3. 代理对象将调用请求封装成 Binder 消息,并通过 Binder 驱动程序发送给服务端。
  4. 服务端接收到 Binder 消息后,解析消息内容,并执行相应的操作。
  5. 服务端执行完操作后,将结果返回给客户端,同样通过 Binder 消息传递。
  6. 客户端接收到结果后,执行相应的逻辑处理。

为什么是 Binder ?

Binder 机制之所以成为 Android 进程间通信的基础,带来了很多便利和好处,

主要归功于以下几个原因:

  • 高效的进程间通信机制:Binder 机制在底层实现了高效的进程间通信机制,包括线程间通信和进程间通信。这使得在 Android 系统中,不同应用程序或者同一个应用程序的不同进程之间能够进行快速、可靠的通信。
  • 抽象了底层细节:使用 Binder 机制时,开发者不需要关心底层通信的实现细节,如进程间通信的具体实现、数据传输方式等。通过 AIDL(Android Interface Definition Language)定义接口后,Binder 机制会自动处理数据的传输和远程方法的调用,使得开发者只需专注于业务逻辑的实现。
  • 提供了灵活的接口定义方式:通过 AIDL 定义接口,开发者可以自由地描述远程服务的接口,包括方法的签名、参数以及返回值。这种灵活的接口定义方式使得不同进程之间的通信更加灵活和方便。
  • 内置了安全机制:Binder 机制内置了安全机制,确保了进程间通信的安全性。例如,Binder 会对传输的数据进行序列化和反序列化,同时通过权限验证等方式确保通信的安全性,防止恶意程序对进程间通信进行攻击。
  • 统一的通信接口:在 Android 系统中,大部分的跨进程通信都是通过 Binder 机制进行的。这种统一的通信接口使得不同应用程序之间的通信更加一致,提高了系统的稳定性和可维护性。

综上所述,Binder 机制作为 Android 系统中进程间通信的基础,通过其高效、抽象、安全、灵活的特性,极大地简化了开发者进行进程间通信的复杂度,提高了系统的性能和稳定性。

这篇关于学习Android的第二十九天的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812366

相关文章

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss