最后
以前一直是自己在网上东平西凑的找,找到的东西也是零零散散,很多时候都是看着看着就没了,时间浪费了,问题却还没得到解决,很让人抓狂。
后面我就自己整理了一套资料,还别说,真香!
资料有条理,有系统,还很全面,我不方便直接放出来,大家可以先看看有没有用得到的地方吧。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
-
(*env)->
调用结构体中的函数指针 -
第二个参数jobject 调用本地函数的java对象就是这个jobject
jstring Java_com_xfhy_jnihelloworld_MainActivity_helloFromC(JNIEnv* env,jobject thiz){
char* str = “hello from c!”;
//到jni.h中找到如下方法 jstring (NewStringUTF)(JNIEnv, const char*);
return (*env)->NewStringUTF(env,str);
}
函数中必须有2个形参:JNIEnv* env,jobject thiz
;如果java中的native函数有形参的话,则需要把这些形参加在JNIEnv* env,jobject thiz
这个2个形参之后.
4.导入
4. jni开发中的常见错误
===============
-
java.lang.UnsatisfiedLinkError: Native method not found: 本地方法没有找到
-
本地函数名写错
-
忘记加载.so文件 没有调用System.loadlibrary
-
findLibrary returned null
-
System.loadLibrary("libhello");
加载动态链接库时 动态链接库名字写错 -
平台类型错误 把只支持arm平台的.so文件部署到了 x86cpu的设备上
在jni目录下创建 Application.mk 在里面指定
APP_ABI := armeabi x86
APP_PLATFORM := android-14
- javah 命令:生成java代码中本地方法名对应的C语言的函数名
使用方法:javah com.xfhy.jnihelloworld.MainActivity
-
jdk 1.7 项目 src目录下运行javah
-
jdk 1.6 项目 bin目录下 classes文件夹
-
javah native方法声明的java类的全类名
5.jni简便开发流程
===========
-
① 写java代码 native 声明本地方法
-
② 添加本地支持 右键单击项目->andorid tools->add native surport
-
如果发现 finish不能点击需要给工作空间配置ndk目录的位置
-
window->preferences->左侧选择android->ndk 把ndk解压的目录指定进来
-
③ 如果写的是.c的文件 先修改一下生成的.cpp文件的扩展名 不要忘了 相应修改Android.mk文件中LOCAL_SRC_FILES的值
-
④ javah生成头文件 在生成的头文件中拷贝c的函数名到.c的文件
-
⑤ 解决CDT插件报错的问题
-
右键单击项目选择 properties 选测 c/c++ general->paths and symbols->include选项卡下->点击add…->file system 选择ndk目录下 platforms文件夹 对应平台下(项目支持的最小版本)
usr 目录下 arch-arm -> include 确定后 会解决代码提示和报错的问题
-
⑥编写C函数 如果需要单独编译一下c代码就在c/c++视图中找到小锤子,点一下小锤子就编译了
-
如果想直接运行到模拟器上 就不用锤子了,直接右键run as,然后就自动编译了
-
⑦ java代码中不要忘了 System.loadlibrary();
static {
System.loadLibrary(“hello”); //加载动态链接库
}
6. Java向C传递一些基本的类型,处理
======================
将一个jstring转换成一个c语言的char* 类型工具方法
char* _JString2CStr(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env, “java/lang/String”);
jstring strencode = (*env)->NewStringUTF(env,“GB2312”);
jmethodID mid = (*env)->GetMethodID(env, clsstring, “getBytes”, “(Ljava/lang/String;)[B”);
jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte(“GB2312”);
jsize alen = (*env)->GetArrayLength(env, barr);
jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
if(alen > 0) {
rtn = (char*)malloc(alen+1); //“\0”
memcpy(rtn, ba, alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env, barr, ba,0);
return rtn;
}
int类型
JNIEXPORT jint JNICALL Java_com_xfhy_javapassdata_JNI_add
(JNIEnv * env, jobject clazz, jint x, jint y){
return x+y; //直接返回x+y
}
String类型
JNIEXPORT jstring JNICALL Java_com_xfhy_javapassdata_JNI_sayHelloInC
(JNIEnv *env, jobject clazz, jstring str){
//将jstring转换成char* 类型
char* cstr = _JString2CStr(env,str);
//调用C语言的strlen测量cstr字符串的长度
int length = strlen(cstr);
int i=0;
for(i=0; i<length; i++){
*(cstr+i) += 1; //将字符串+1
}
return (env)->NewStringUTF(env,cstr); //将char 类型转换成String类型返回
}
int[]类型
JNIEXPORT jintArray JNICALL Java_com_xfhy_javapassdata_JNI_arrElementsIncrease
(JNIEnv *env, jobject clazz, jintArray jArray) {
//jsize (GetArrayLength)(JNIEnv, jarray); 返回数组长度
int length = (*env)->GetArrayLength(env,jArray);
//jint* (GetIntArrayElements)(JNIEnv, jintArray, jboolean*); 最后一个参数表示是否拷贝,可以不用传值
//返回int* 返回该数组的首地址 这样就可以直接通过该指针直接操作该数组了
int* cArray = (*env)->GetIntArrayElements(env,jArray,NULL);
int i;
for(i=0; i<length; i++) {
*(cArray+i) += 10;
}
return jArray; //直接将原数组返回(这时已经是修改过了的)
}
7.C代码中向logcat输出内容
=================
1.Android.mk文件增加以下内容
LOCAL_LDLIBS += -llog
2.C代码中增加以下内容
#include <android/log.h>
#define LOG_TAG “xfhy”
#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, VA_ARGS)
#define LOGI(…) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, VA_ARGS)
-
define C的宏定义 起别名 #define LOG_TAG “xfhy” 给”xfhy”起别名LOG_TAG
-
#define LOGI(…) android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS),ANDROID_LOG_DEBUG表示优先级 debug ANDROID_LOG_INFO表示info 这些在log.h中可以看到
-
给 __android_log_print函数起别名 写死了前两个参数 第一个参数 优先级 第二个参数TAG
-
VA_ARGS:是可变参数的固定写法
-
LOGI(…)在调用的时候 用法跟printf()一样
8. C代码回调java方法
===============
首先需要了解:
Java反射
public class Demo {
public static void main(String[] args) {
//1.获取字节码对象
Class util = Utils.class;
try {
//2.获取Method对象 方法名,参数类型
Method method = util.getMethod(“test”, String.class);
//3.通过字节码对象创建一个Obejct
Object obj = util.newInstance();
//4.通过对象调用方法 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法
method.invoke(obj, “hello”);
} catch (Exception e) {
e.printStackTrace();
}
}
public class Utils {
public void test(String string) {
System.out.println(string);
}
}
}
C代码回调java方法
-
① 找到字节码对象
-
//jclass (FindClass)(JNIEnv, const char*);
-
//第二个参数 要回调的java方法所在的类的路径 “com/itheima/callbackjava/JNI”
-
② 通过字节码对象找到方法对象
-
//jmethodID (GetMethodID)(JNIEnv, jclass, const char*, const char*);
-
第二个参数 字节码对象 第三个参数 要反射调用的java方法名 第四个参数 要反射调用的java方法签名
-
javap -s 要获取方法签名的类的全类名 项目/bin/classes 运行javap
-
③ 通过字节码创建 java对象(可选) 如果本地方法和要回调的java方法在同一个类里,可以直接用 jni传过来的java对象 调用创建的Method
-
jobject obj =(*env)->AllocObject(env,claz);
-
当回调的方法跟本地方法不在一个类里 需要通过刚创建的字节码对象手动创建一个java对象
-
再通过这个对象来回调java的方法
-
需要注意的是 如果创建的是一个activity对象 回调的方法还包含上下文 这个方法行不通!!!回报空指针异常
-
④ 反射调用java方法
总结
学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
最后如何才能让我们在面试中对答如流呢?
答案当然是平时在工作或者学习中多提升自身实力的啦,那如何才能正确的学习,有方向的学习呢?有没有免费资料可以借鉴?为此我整理了一份Android学习资料路线:
这里是一部分我工作以来以及参与过的大大小小的面试收集总结出来的一套BAT大厂面试资料专题包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家。
好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
最后,祝愿即将跳槽和已经开始求职的大家都能找到一份好的工作!
这些只是整理出来的部分面试题,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。喜欢的话麻烦点击一个喜欢再关注一下~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划**。来看看同行们都是如何突破现状,怎么学习的,来吸收他们的面试以及工作经验完善自己的之后的面试计划及职业规划。
最后,祝愿即将跳槽和已经开始求职的大家都能找到一份好的工作!
这些只是整理出来的部分面试题,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。喜欢的话麻烦点击一个喜欢再关注一下~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!