深入浅出安卓中的C++
一、安卓为啥要用C++?
安卓就像混血儿:
- Java/Kotlin:处理UI、业务逻辑(像大脑)
- C++:干重活(像肌肉):
- 高性能计算(游戏/音视频)
- 复用现有C++库(OpenCV/FFmpeg)
- 底层硬件操作(传感器/图形渲染)
二、JNI基础(Java与C++的翻译官)
1. JNI工作原理
Java ->> C++调用native方法
C++调用native方法 ->> Java通过JNIEnv操作Java
2. 定义native方法
// Java层声明
public class NativeLib {
public native int add(int a, int b); // native关键字
}
3. C++实现
// native-lib.cpp
#include <jni.h>
extern "C" JNIEXPORT jint JNICALL
Java_com_example_NativeLib_add(JNIEnv* env, jobject thiz, jint a, jint b) {
return a + b; // 简单的加法
}
方法名规则:Java_包名_类名_方法名
三、NDK开发四步走
1. 配置NDK(Android Studio)
// build.gradle
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++17"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt" // CMake配置文件
}
}
}
2. 编写CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project("native-lib")
add_library( # 库名称
native-lib
# 类型:SHARED动态库
SHARED
# 源文件
src/main/cpp/native-lib.cpp )
find_library( # 查找系统库
log-lib
log )
target_link_libraries( # 链接库
native-lib
${log-lib} )
3. Java加载库
public class NativeLib {
static {
System.loadLibrary("native-lib"); // 加载so库
}
public native String getMessage();
}
4. C++与Java交互
// 调用Java方法示例
extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeLib_callJavaMethod(JNIEnv* env, jobject thiz) {
jclass clazz = env->GetObjectClass(thiz);
jmethodID method = env->GetMethodID(clazz, "showToast", "(Ljava/lang/String;)V");
jstring msg = env->NewStringUTF("来自C++的问候");
env->CallVoidMethod(thiz, method, msg);
}
四、数据类型对照表
| Java类型 | C++类型 | JNI类型 |
|---|---|---|
| boolean | bool | jboolean |
| int | int32_t | jint |
| long | int64_t | jlong |
| String | char* | jstring |
| byte[] | uint8_t* | jbyteArray |
五、性能优化技巧
1. 减少JNI调用
错误示范:
// Java循环调用native方法
for (int i = 0; i < 1000; i++) {
nativeProcess(data[i]); // 每次都有JNI开销
}
正确做法:
// 一次性传递数据
nativeBatchProcess(data); // C++内部循环
2. 直接内存访问
// 获取Java数组的直接指针
jbyte* buffer = env->GetByteArrayElements(javaArray, NULL);
// 直接操作内存...
env->ReleaseByteArrayElements(javaArray, buffer, 0); // 必须释放!
3. 线程管理
- JNIEnv:每个线程需要独立获取
JavaVM* gVm; JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { gVm = vm; // 保存全局引用 return JNI_VERSION_1_6; } void nativeThread() { JNIEnv* env; gVm->AttachCurrentThread(&env, NULL); // 使用env... gVm->DetachCurrentThread(); }
六、实战案例:图像处理
1. Java层定义
public class ImageProcessor {
public native void blurBitmap(Bitmap bitmap, int radius);
}
2. C++实现
#include <android/bitmap.h>
extern "C" JNIEXPORT void JNICALL
Java_com_example_ImageProcessor_blurBitmap(JNIEnv* env, jobject, jobject bitmap, jint radius) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, bitmap, &info);
void* pixels;
AndroidBitmap_lockPixels(env, bitmap, &pixels); // 锁定内存
// 使用C++实现高斯模糊(示例伪代码)
applyGaussianBlur((uint8_t*)pixels, info.width, info.height, radius);
AndroidBitmap_unlockPixels(env, bitmap); // 解锁
}
七、常见问题
1. Crash排查
- 错误信息:
java_vm_ext.cc:577] JNI DETECTED ERROR IN APPLICATION - 解决步骤:
- 检查
adb logcat崩溃堆栈 - 使用
addr2line定位so库错误位置ndk-stack -sym ./obj/local/armeabi-v7a -dump crash.log
- 检查
2. 内存泄漏
- JNI引用:及时删除局部引用
jstring jstr = env->NewStringUTF("hello"); // 使用完后... env->DeleteLocalRef(jstr);
3. 兼容性问题
- ABI适配:为不同CPU架构编译
android { defaultConfig { ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86' } } }
八、进阶方向
1. 现代C++特性
- 智能指针:避免内存泄漏
std::unique_ptr<int[]> buffer(new int[100]); - 多线程:
std::thread+ 原子操作
2. 混合调试
- Android Studio:同时调试Java和C++代码
- LLDB:命令行调试工具
3. 高性能库
- NEON指令集:ARM芯片加速
- RenderScript:Google提供的并行计算框架
九、终极口诀
"JavaC++手拉手,JNI来做翻译官
NDK配置CMake,类型转换要小心
减少跨语言调用,直接访问性能高
内存线程管理好,兼容问题早排查"
掌握安卓C++开发,你就能让App既聪明又有力气! 💪🧠