我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android AIDL通信DeadObjectException解决方法示例

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android AIDL通信DeadObjectException解决方法示例

崩溃来源

使用过AIDL进行跨进程通信的同学,肯定遇到过DeadObjectException这个崩溃,那么这个崩溃是怎么来的,我们又该如何解决它呢?今天这篇文章就来聊一聊。

首先,这个崩溃的意思是,多进程在进行跨进程Binder通信的时候,发现通信的Binder对端已经死亡了。

抛出异常的Java堆栈最后一行是BinderProxy.transactNative,所以我们从这个方法入手,看看崩溃是在哪里产生的。

很显现,transactNative对应的是一个native方法,我们找到对应的native方法,在android_util_Binder.cpp中。

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    // 如果data数据为空,直接抛出空指针异常
    if (dataObj == NULL) {
        jniThrowNullPointerException(env, NULL);
        return JNI_FALSE;
    }
    // 将Java层传入的对象转换为C++层的指针,如果转换出错,中断执行,返回JNI_FALSE
    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }
    // 获取C++层的Binder代理对象指针
    // 如果获取失败,会抛出IllegalStateException
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }
    // 调用BpBinder对象的transact方法
    status_t err = target->transact(code, *data, reply, flags);
    // 如果成功,返回JNI_TRUE,如果失败,返回JNI_FALSE
    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }
    // 处理异常情况的抛出
    signalExceptionForError(env, obj, err, true , data->dataSize());
    return JNI_FALSE;
}

可以看到,这个方法主要做的事情是:

  • Java层传入的data,转换成C++层的指针
  • 获取C++层的Binder代理对象
  • 调用BpBinder对象的transact方法
  • 处理transact的结果,抛出异常

接下来我们看看,BpBindertransact方法。

status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // 首先判断Binder对象是否还存活,如果不存活,直接返回DEAD_OBJECT
    if (mAlive) {
            ...
            status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
            return status;
    }
    return DEAD_OBJECT;
}

transact的具体方法,我们这里先不讨论。我们可以看到,在这里会判断当前的Binder对象是否alive,如果不alive,会直接返回DEAD_OBJECT的状态。

返回的结果,在android_util_BindersignalExceptionForError中处理。

void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
        bool canThrowRemoteException, int parcelSize)
{
       // 省略其他异常处理的代码
        ....
        case DEAD_OBJECT:
            // DeadObjectException is a checked exception, only throw from certain methods.
            jniThrowException(env, canThrowRemoteException
                    ? "android/os/DeadObjectException"
                            : "java/lang/RuntimeException", NULL);
            break;
}

这个方法,其实包含非常多异常情况的处理。为了看起来更清晰,这里我们省略了其他异常的处理逻辑,只保留了DEAD_OBJECT的处理。可以很明显的看到,在这里我们抛出了DeadObjectException异常。

解决方法

通过前面的源码分析,我们知道DeadObjectException是发生在,当我们调用transact接口发现Binder对象不再存活的情况。

解决方案也很简单,就是当这个Binder对象死亡之后,不再调用transact接口。

方法1 调用跨进程接口之前,先判断Binder是否存活

这个方案比较简单粗暴,就是在多有调用跨进程接口的地方,都加一个Binder是否存活的判断。

        if (mService != null && mService.asBinder().isBinderAlive()) {
            mService.test();
        }

我们来看下isBinderAlive的源码,就是判断mAlive标志位是否为0。

bool BpBinder::isBinderAlive() const
{
    return mAlive != 0;
}

方法2 监听Binder死亡通知

先初始化一个DeathRecipient,用来监听死亡通知。

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            // 解绑当前监听,重新启动服务
            mService.asBinder().unlinkToDeath(mDeathRecipient, 0);
            if (mService != null)
                bindService(new Intent("com.service.bind"), mService, BIND_AUTO_CREATE);
        }
    };

在这个死亡监听里,我们可以选择几种处理方式:

  • 什么都不做,直接将mService设置为空
  • 再次尝试启动和绑定服务

onServiceConnected方法中,注册死亡监听:

public void onServiceConnected(ComponentName name, IBinder service) {          
    mService = IServiceInterface.Stub.asInterface(service);     
    //获取服务端提供的接口
    try {
        // 注册死亡代理
        if(mService != null){
            service.linkToDeath(mDeathRecipient, 0); 
        }       
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

总结

跨进程通信时,无法避免出现Binder对端挂掉的情况,所以在调用相关通信接口时,一定要判断连接是否可用,否则就会出现DeadObjectException的崩溃。

以上就是Android AIDL通信DeadObjectException解决方法示例的详细内容,更多关于Android AIDL通信的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android AIDL通信DeadObjectException解决方法示例

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android AIDL通信DeadObjectException解决方法示例

这篇文章主要为大家介绍了Android AIDL通信DeadObjectException解决的方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-09

Android AIDL通信DeadObjectException解决方法是什么

这篇文章主要介绍了Android AIDL通信DeadObjectException解决方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android AIDL通信DeadObjectException
2023-07-05

android中的AIDL进程间通信示例

关于IPC应该不用多介绍了,Android系统中的进程之间不能共享内存,那么如果两个不同的应用程序之间需要通讯怎么办呢?比如公司的一个项目要更新,产品的需求是依附于当前项目开发一个插件,但是呢这个插件功能以及界面比较复杂,不能和当前项目在一
2022-06-06

Android AIDL实现跨进程通信的示例代码

AIDL是Android接口定义语言,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。实现步骤例:用 A程序去访问 B程序的MyService.java服务 在B
2023-05-30

Android编程实现AIDL(跨进程通信)的方法详解

本文实例讲述了Android编程实现AIDL(跨进程通信)的方法。分享给大家供大家参考,具体如下: 一. 概述: 跨进程通信(AIDL),主要实现进程(应用)间数据共享功能。 二. 实现流程: 1. 服务器端实现: (1)目录结构,如下图:
2022-06-06

实例讲解Android中的AIDL内部进程通信接口使用

首先描述下我们想要实现的内容,我们希望在一个应用中通过点击按钮,去操作另一个进程中应用的音乐播放功能。如图,我们点击“播放”时,系统就会去远程调用我们提供的一个service(与当前service不是同一个应用哦),然后操作service中
2022-06-06

Android 使用【AIDL】调用外部服务的解决方法

在Android 中有一种服务说是服务其实倒不如说是一个接口,这个接口名为:Android Interface Definition Language ,这个接口可提供跨进程访问服务,英文缩写为:AIDL。 此种服务的好处在于,多个应用程序
2022-06-06

Flutter与WebView通信方案示例详解

这篇文章主要为大家介绍了Flutter与WebView通信方案示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-04

Android发送短信方法实例详解

本文实例讲述了Android发送短信方法。分享给大家供大家参考,具体如下: 短信和打电话一样,都是android手机的基本功能,下面以实例说明android如何实现发送短信的功能。 程序如下所示:import java.util.regex
2022-06-06

Android应用开发中Fragment与Activity间通信示例讲解

首先,如果你想在android3.0及以下版本使用fragment,你必须引用android-support-v4.jar这个包 然后你写的activity不能再继承自Activity类了,而是要继承android.support.v4.a
2022-06-06

Android自定义View展示Wifi信号强弱指示方法示例

前言最近因为工作的需要,要自定义展示Wifi信号强弱的需要,就通过利用系统广播的方式实现了一个自定义View——WifiStateView,下面话不多说了,感兴趣的朋友们一起来看看详细的介绍吧。实现的效果图如下所示:用不同的图片来表示Wif
2023-05-30

Java使用Socket通信传输文件的方法示例

本文实例讲述了Java使用Socket通信传输文件的方法。分享给大家供大家参考,具体如下:前面几篇文章介绍了使用Java的Socket编程和NIO包在Socket中的应用,这篇文章说说怎样利用Socket编程来实现简单的文件传输。这里由于前
2023-05-31

Android编程操作手机通讯录的方法示例

本文实例讲述了Android编程操作手机通讯录的方法。分享给大家供大家参考,具体如下:手机通讯录的操作是经常被用到的,例如添加联系人,删除联系人或者取得联系人信息。类似的操作还有收藏夹的操作,下面就针对通讯录的操作来做个小例子。同样的这次也
2023-05-30

android通过Location API显示地址信息的实现方法

本文实例讲述了android通过Location API显示地址信息的实现方法。分享给大家供大家参考。具体如下: android的Locatin API,可以通过Geocoder类,显示具体经纬度的地址信息。如: 通过Geocoder的方法
2022-06-06

Android 通过productFlavors实现多渠道打包方法示例

这篇文章主要为大家介绍了Android 通过productFlavors实现多渠道打包方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-12

android真机调试时无法显示logcat信息的解决方法介绍

android真机调试时无法显示logcat信息的解决方法介绍: window-->show view-->android->devices, 打开devices,点击右边的截屏图片的按钮。等到出现截图的时候,logcat就出来信息了!您可
2022-06-06

android教程之service使用方法示例详解

Service的生命周期 (适用于2.1及以上) 1. 被startService的无论是否有任何活动绑定到该Service,都在后台运行。onCreate(若需要) -> onStart(int id, Bundle args). 多次
2022-06-06

Android开发之使用通知栏显示提醒信息的方法

本文实例讲述了Android开发之使用通知栏显示提醒信息的方法。分享给大家供大家参考,具体如下: 用通知栏来提醒public void notifyKJ() {//获得通知管理器,通知是一项系统服务NotificationManager m
2022-06-06

电脑显示器无信号的解决方法

这篇文章主要介绍了电脑显示器无信号的解决方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、如果主机正常开机运行,那么可能是显示器与主机相连接的信号线松脱或接触不良,需要检
2023-06-27

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录