文/ 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调用框架。

Tamic: http://blog.csdn.net/sk719887916/

React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》的更多相关文章

  1. ReactNative 4Android源码分析二: 《JNI智能指针之实现篇》

    文/Tamic http://blog.csdn.net/sk719887916/article/details/53462268 回顾 上一篇介绍了<ReactNative4Android源码 ...

  2. Android源码分析(十三)----SystemUI下拉状态栏如何添加快捷开关

    一:如何添加快捷开关 源码路径:frameworks/base/packages/SystemUI/res/values/config.xml 添加headset快捷开关,参考如下修改. Index: ...

  3. Android源码分析(十一)-----Android源码中如何引用aar文件

    一:aar文件如何引用 系统Settings中引用bidehelper-1.1.12.aar 文件为例 源码地址:packages/apps/Settings/Android.mk LOCAL_PAT ...

  4. Android源码分析-全面理解Context

    前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...

  5. Android源码分析(六)-----蓝牙Bluetooth源码目录分析

    一 :Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...

  6. Android源码分析(十七)----init.rc文件添加脚本代码

    一:init.rc文件修改 开机后运行一次: chmod 777 /system/bin/bt_config.sh service bt_config /system/bin/bt_config.sh ...

  7. Android源码分析(十六)----adb shell 命令进行OTA升级

    一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...

  8. Android源码分析(十五)----GPS冷启动实现原理分析

    一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...

  9. Android源码分析(十四)----如何使用SharedPreferencce保存数据

    一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...

随机推荐

  1. 数据库性能优化(database tuning)性能优化绝不仅仅只是索引

    一毕业就接触优化方面的问题,专业做优化也有至少5年之多的时间了,可现在还是经常听到很多人认为优化很简单,就是建索引的问题,这确实不能怪大家,做这行20多年的时间里,在职业生涯的每个阶段,几乎都能听到这 ...

  2. Python面向对象——内置对象的功能扩展

    1.扩展Python内置类 Python的数据类型 列表(list).字典(dict).集合(set).文件(file).字符串(str),这些都是对象 扩展list的功能,详解如图: 我们给列表添加 ...

  3. ACE工具概述

    一:ACE简介 ADAPTIVE 通信环境(ACE,ADAPTIVE Communication Enviroment)是一种广泛的主机基础设施中间件,ACE可以免费获得,可以在http://ace. ...

  4. css 相关算法

    计算 em 目标像素 除 基准像素 等于 em倍数结果: 14 / 16 = 0.875em 0.875倍也就是 14 像素 计算百分比 目标像素 除 父类总宽度 乘 一百:90 / 200 * 10 ...

  5. java中lamda表达式的应用

    lamda表达式主要是为了解决匿名内部类的繁琐过程 范例:简单的lamda表达式 此处使用匿名内部类 package com.java.demo; interface IMessage{ public ...

  6. 手写简单的jq雪花飘落

    闲来无事,准备写个雪花飘落的效果,没有写太牛逼的特效,极大的简化了代码量,这样容易读取代码,用起来也很简单,对于那些小白简直是福利啊,简单易读易学.先直接上代码吧,然后再一一讲解,直接复制粘贴就可以拿 ...

  7. UOJ #206. 【APIO2016】Gap

    Description Solution 第一个子任务,直接从 \((a[i],a[j])\) 推出 \((a[i+1],a[j-1])\) 就行了,只需要 \(\frac{N+1}{2}\) 第二个 ...

  8. 洛谷P3233 [HNOI2014]世界树

    虚树= = #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring&g ...

  9. ●Joyoi Easy

    题链: http://www.joyoi.cn/problem/tyvj-1952题解: 概率dp (先做的BZOJ 4318: OSU![本人题解],然后就感觉这个题很简单了) 令p[i]表示第i个 ...

  10. poj 3525 凸多边形多大内切圆

    Most Distant Point from the Sea Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4758   ...