React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》

文/ Tamic: http://blog.csdn.net/sk719887916/article/details/53455441
原文:http://blog.csdn.net/eewolf/article/details/52403918
导读
React Native 发布以来将近一年多了,也被抄的火爆到不行,包括RN的中文网和各种资料也很多,加之SE5,Se6语法升级,学习成本并不在RN环境搭建和入门,关键还是对JS的掌握入门,不管你是用Native开发,h5开发,还是React Native的开发,都应该明白上层语言和底层交互,都离不开c, 今天就介绍下native中Jni过程中的指针运用。文章适合入门了RN的朋友看,入门资料:Android 开发者转 React Native 必看教程汇总
JNI指针
通常的app中, JNI提供的native函数主要充当Java类的扩展,逻辑层在Java端,JNI端较少使用OOP的设计思想。 而对于native端功能较重的模块,例如开源的阅读器FBReader,native端与Java端有较多交互,即native会主动创建Java对象并调用它们的方法以实现功能,这时就需要考虑将native至Java的操作与访问框架化,形成更高层次的封装,以避免直接使用原始的JNI反射API集去操作Java对象。
对于ReactNative For Android而言,这套访问框架尤其重要,其核心就是JNI智能指针这个基本数据类型。它的实现基于C11标准,将先用几篇对这套native至Java的操作框架进行介绍,为后续分析打下良好基础。
Native引用
首先回顾一下Java Object(jobject)在native端的三种引用类型:
全局引用
类似于C语言中的全局变量。使用NewGlobalRef创建,支持跨线程访问 ,在调用释放DeleteGlobalRef销毁前,GC无法回收该引用对应的java object。
局部引用
概念上与C语言中的局部变量有相似点,但不等同。使用NewLocalRef创建, 只能在本线程内安全访问,当创建该引用的native调用链返回至JVM时,未销毁的局部引用会被JVM自动GC回收。但由于局部引用表容量有限,在返回至JVM前,可以调用DeleteLocalRef先行销毁,避免局部引用表超限引起崩溃。
弱全局引用
与全局引用一样具有全局作用域,但不会影响GC回收, GC可以随时回收该引用对应的java object。使用NewWeakGlobalRef创建,当需要使用时,需要将其升级为全局引用或者局部引用,若已被回收,会返回null,使用DeleteWeakGlobalRef销毁。该引用类型使用场景较少。
由上可见,JNI智能指针的第一个需求,就是要自动管理jobject的生命周期,当进入与离开对应作用域时,需要自动调用对应生命周期的创建与销毁函数。这在C++中,通常会结合构造与析构函数来进行配对调用。若功能仅限于此,就与普通的智能指针和mutext锁管理机制类似了,更重要的需求是在C++层提供与被管理的Java对象镜像结构的C++对象,形成高层次封装。这样,对jobject的访问与操作就会被封装在对应的镜像C++对象中,相关JNI反射调用的细节被隐藏,对于其他native模块而言,与Java层的交互被转化成了与这些镜像C++对象的交互,整个实现风格OOP化了。这些镜像C++对象被称为wrapper对象,其定义代码位于ReactAndroid/src/main/jni/first-party/fb/include/fb/fbjni/CoreClasses.h文件中。
先看一个使用范例:
struct MyClass : public JavaClass<MyClass> {
constexpr static auto kJavaDescriptor = "Lcom/example/package/MyClass;";
void foo() {
static auto method = javaClassStatic()->getMethod<void()>("foo");
method(self());
}
static local_ref<javaobject> create(int i) {
return newInstance(i);
}
};
auto obj = MyClass::create(10);
obj->foo();
Native的需求是在native端创建com.example.package.MyClass这个自定义的Java类的对象,并访问它的foo方法。
实现步骤
例子中实现的步骤是:
定义java的MyClass的wrapper C++类MyClass,所有wrapper均需要继承于JavaClass的一个模板实例,并将自身类型做为JavaClass的第一个模板类型参数,以供JavaClass获取具体wrapper的类型。
给static成员变量kJavaDescriptor赋值为对应Java类的全类名。
在wrapper类实现镜像方法foo(), 其会获取jclass的包装类JClass对象,并获取jmethod的包装类JMethod进行调用。
create工厂方法中使用newInstance构建镜像对象的实例,并将其存至局部智能指针local_ref。这样就可以通过智能指针访问wrapper class提供的foo方法,实现了native至Java的镜像映射。
除了实现对一个java类的的映射,还需要支持对java继承关系的映射。若java的MyClass有一子类MyChildClass,native层为其建立的wrapper class可如下:
struct MyChildClass : public JavaClass<MyChildClass, MyClass> {
constexpr static auto kJavaDescriptor = "Lcom/example/package/MyChildClass;";
};
这里需要用到JavaClass的第二个模板参数,设为MyClass,它是JavaClass
疑问
这就带来几个问题:
javaObject与jobject的关系是什么?
为什么智能指针的模板参数能够接受多种类型?
模板参数起到的作用是什么?
结尾
这些问题将在下一篇智能指针的具体实现篇中解答。
总结一下,在ReactNative for Android中,为了简化native层对Java层的调用,提供了镜像结构的wrapper class,结合智能指针,将jobject的生命周期管理、java method的反射调用等“样板”代码封装起来,是比较优雅的JNI调用框架。
React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》的更多相关文章
- ReactNative 4Android源码分析二: 《JNI智能指针之实现篇》
文/Tamic http://blog.csdn.net/sk719887916/article/details/53462268 回顾 上一篇介绍了<ReactNative4Android源码 ...
- Android源码分析(十三)----SystemUI下拉状态栏如何添加快捷开关
一:如何添加快捷开关 源码路径:frameworks/base/packages/SystemUI/res/values/config.xml 添加headset快捷开关,参考如下修改. Index: ...
- Android源码分析(十一)-----Android源码中如何引用aar文件
一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- Android源码分析(六)-----蓝牙Bluetooth源码目录分析
一 :Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...
- Android源码分析(十七)----init.rc文件添加脚本代码
一:init.rc文件修改 开机后运行一次: chmod 777 /system/bin/bt_config.sh service bt_config /system/bin/bt_config.sh ...
- Android源码分析(十六)----adb shell 命令进行OTA升级
一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...
- Android源码分析(十五)----GPS冷启动实现原理分析
一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...
- Android源码分析(十四)----如何使用SharedPreferencce保存数据
一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...
随机推荐
- 使用 WTForms 进行表单验证的例子
#使用 WTForms 进行表单验证的例子 from wtforms import Form from wtforms import BooleanField from wtforms import ...
- [转]Python UnicodeEncodeError: 'gbk' codec can't encode character 解决方法
使用Python写文件的时候,或者将网络数据流写入到本地文件的时候,大部分情况下会遇到:UnicodeEncodeError: 'gbk' codec can't encode character ' ...
- 参加Java培训到底靠不靠谱?
导读 科技越发展,社会越进步,人们越便利,便衍生出更多的人从事程序员这个高大上的职业,可哈尔滨Java培训学校这么多,到底靠不靠谱,会不会处处是陷阱,爱尚实训帮你擦亮眼 随着时代的发展,越来越多的人对 ...
- Python系列之 - 上下文管理协议
with obj as f: '代码块' 1.with obj ---->触发obj.__enter__(),拿到返回值 2.as f----->f=返回值. 3.with obj as ...
- [ZJOI2015]幻想乡战略游戏
Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...
- [POI2000] 最长公共子串
给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务 从文件中读入单词 计算最长公共子串的长度 输出结果到文件 输入 文件的第一行是整数 n,1<=n<=5,表示单词的数量.接 ...
- spring boot新建项目启动报:Unregistering JMX-exposed beans on shutdown
原因为:SpringBoot内置Tomcat没有正常启动,在pom.xml 中添加: <dependency> <groupId>org.springframework.boo ...
- Angular中 build的时候遇到的错误--There are multiple modules with names that only differ in casing
今天早上遇到一个Angular的编译的时候的错误 具体信息: There are multiple modules with names that only differ in casing.This ...
- 分区工具PQ
http://www.disktool.cn/jiaocheng/resize-partition.html
- ChatGirl is an AI ChatBot based on TensorFlow Seq2Seq Model
Introduction [Under developing,it is not working well yet.But you can just train,and run it.] ChatGi ...