最近的学习真的比较困难,因为学习了SDK开发项目后,做了一些简单的项目后,觉得在UI线程中加载较多图片时,总会出现卡顿的感觉,特别是手指滑动下拉时,这种卡顿更易察觉到,而java的结构化开发能力确实是很强大的,使用java开发确实是一件非常享受的事情,但是java在一些高密度的计算中是没有什么优势的,在享受内存自动回收时也会遇到一些不如意的事。任何语言或事物,总会有优缺点,这是java如此简单易用的一个副作用。所以为了不使java的副作用危害到开发者使用java,java产生了一种非常有吸引力的的技术JNI技术,这种技术可以让Java调用C/C++和其他的语言所写的程序。而这种技术也在android中得以支持--NDK, NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk,使用起来非常方便。
说了一堆的废话,接下来记录下自己最近所学习到的东西,可以说NDK重要的学习资料之一就是android的官方网站提供的资料,包括下载了NDK后,也能看到一些简单的使用了NDK的项目源码,这些源码能让我们知道android官方建议我们如何使用NDK,甚至可以用纯C/C++语言开发应用,但这并不是我感兴趣的,具体原因就不说了。
按照官方的使用方式还是比较简单的,这里写了一个用C语言提取照片灰度图的函数,并在java中调用
先写java代码
public class PhotoProcessingActivity extends Activity{ private Bitmap bmOriginal,bmGray; private ImageView iv; private Button btGray,btOpen; static{ System.loadLibrary("PhotoProcessing"); } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.photo_processing_activity); setup(); } public void setup(){ iv = (ImageView) findViewById(R.id.showPhoto); bmOriginal = ImageShare.mBitmap; iv.setImageBitmap(bmOriginal); btGray = (Button) findViewById(R.id.btGray); btGray.setOnClickListener(onclick); btOpen = (Button) findViewById(R.id.btOpen); btOpen.setOnClickListener(onclick); } OnClickListener onclick = new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()){ case R.id.btGray: bmGray = Bitmap.createBitmap(bmOriginal.getWidth(), bmOriginal.getHeight(), Config.ALPHA_8); grayPhoto(bmOriginal, bmGray); iv.setImageBitmap(bmGray); break; case R.id.btOpen: Intent intent = new Intent(PhotoProcessingActivity.this, SurfaceProcessingActivity.class); startActivity(intent); break; } } }; public native void grayPhoto(Bitmap bmOriginal,Bitmap bmGray); }
使用javah工具得到头文件PhotoProcessingActivity.h并且添加处理图片所需的一些头文件,这些头文件都是NDK中的include中自带的,使用时可以把把该文件夹链接进去
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_photoprocessing_activity_PhotoProcessingActivity */ #include <android/bitmap.h> #include <android/log.h> #include <math.h> #include <string.h> #ifndef _Included_com_example_photoprocessing_activity_PhotoProcessingActivity #define _Included_com_example_photoprocessing_activity_PhotoProcessingActivity #ifdef __cplusplus extern "C" { #endif #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_PRIVATE 0L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_READABLE 1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_WORLD_WRITEABLE 2L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_APPEND 32768L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_MULTI_PROCESS 4L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING #define com_example_photoprocessing_activity_PhotoProcessingActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_AUTO_CREATE 1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_DEBUG_UNBIND 2L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_NOT_FOREGROUND 4L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ABOVE_CLIENT 8L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ALLOW_OOM_MANAGEMENT 16L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_WAIVE_PRIORITY 32L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_IMPORTANT 64L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY #define com_example_photoprocessing_activity_PhotoProcessingActivity_BIND_ADJUST_WITH_ACTIVITY 128L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE #define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_INCLUDE_CODE 1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY #define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_IGNORE_SECURITY 2L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED #define com_example_photoprocessing_activity_PhotoProcessingActivity_CONTEXT_RESTRICTED 4L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED #define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_CANCELED 0L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK #define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_OK -1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER #define com_example_photoprocessing_activity_PhotoProcessingActivity_RESULT_FIRST_USER 1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE #define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DISABLE 0L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER #define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_DIALER 1L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT #define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SHORTCUT 2L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL #define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L #undef com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL #define com_example_photoprocessing_activity_PhotoProcessingActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L /* * Class: com_example_photoprocessing_activity_PhotoProcessingActivity * Method: grayPhoto * Signature: (Landroid/graphics/Bitmap;Landroid/graphics/Bitmap;)V */ /** * xuan */ #define LOG_TAG "PhotoProcessing" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) typedef struct { uint8_t alpha; uint8_t red; uint8_t green; uint8_t blue; } argb; JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto (JNIEnv *, jobject, jobject, jobject); #ifdef __cplusplus } #endif #endif
接着编写C代码
#include "PhotoProcessingActivity.h" JNIEXPORT void JNICALL Java_com_example_photoprocessing_activity_PhotoProcessingActivity_grayPhoto( JNIEnv *env, jobject photoProcessingActivity, jobject bmOriginal, jobject bmGray) { AndroidBitmapInfo origanalColor; void* pixelscolor; AndroidBitmapInfo infogray; void* pixelsgray; int ret; int y; int x; LOGI("In convertToGray"); if ((ret = AndroidBitmap_getInfo(env, bmOriginal, &origanalColor)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } if ((ret = AndroidBitmap_getInfo(env, bmGray, &infogray)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } LOGI( "original image :: width is %d; height is %d; stride is %d; format is %d;flags is %d,stride is %u", origanalColor.width, origanalColor.height, origanalColor.stride, origanalColor.format, origanalColor.flags, origanalColor.stride); if (origanalColor.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { LOGE("Bitmap format is not RGBA_8888 !"); //return; } if (origanalColor.format == ANDROID_BITMAP_FORMAT_RGB_565) { LOGI("Original Image is ANDROID_BITMAP_FORMAT_RGB_565"); if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } // modify pixels with image processing algorithm for (y = 0; y < origanalColor.height; y++) { __uint16_t * line = (__uint16_t *) pixelscolor; uint8_t * grayline = (uint8_t *) pixelsgray; for (x = 0; x < origanalColor.width; x++) { grayline[x] = (uint8_t)(((line[x] >> 11 <<3) + (line[x] >> 5 & 63 * 16) + (line[x]&31 * 8)) / 3); //LOGI("%d %d %d %d",line[x].alpha,line[x].red,line[x].green,line[x].blue); /*if(x ==0){ LOGI("line:%o grayline %o ",line[x],grayline[x]); }*/ } pixelscolor = (char *) pixelscolor + origanalColor.stride; pixelsgray = (char *) pixelsgray + infogray.stride; } LOGI("unlocking pixels"); AndroidBitmap_unlockPixels(env, bmOriginal); AndroidBitmap_unlockPixels(env, bmGray); LOGI("Return !! "); return ; } LOGI( "gray image :: width is %d; height is %d; stride is %d; format is %d;flags is %d %d,stride is %u", infogray.width, infogray.height, infogray.stride, infogray.format, infogray.flags, infogray.stride); if (infogray.format != ANDROID_BITMAP_FORMAT_A_8) { LOGE("Bitmap format is not A_8 !"); return; } if ((ret = AndroidBitmap_lockPixels(env, bmOriginal, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } if ((ret = AndroidBitmap_lockPixels(env, bmGray, &pixelsgray)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } // modify pixels with image processing algorithm for (y = 0; y < origanalColor.height; y++) { argb * line = (argb *) pixelscolor; uint8_t * grayline = (uint8_t *) pixelsgray; for (x = 0; x < origanalColor.width; x++) { grayline[x] = (line[x].red + line[x].green + line[x].blue) / 3; } pixelscolor = (char *) pixelscolor + origanalColor.stride; pixelsgray = (char *) pixelsgray + infogray.stride; } LOGI("unlocking pixels"); AndroidBitmap_unlockPixels(env, bmOriginal); AndroidBitmap_unlockPixels(env, bmGray); }
编写Android.mk文件,该文件主要是指明要使用的.so文件,并且生成我们自己的.so文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := PhotoProcessing LOCAL_SRC_FILES := PhotoProcessing.cpp LOCAL_LDLIBS := -llog -ljnigraphics include $(BUILD_SHARED_LIBRARY)
关键的一些代码就是这些了,其中处理的灰度算法可能不是非常优化,这其中处理RGB565部分是我自己根据图像处理中灰度的定义所写的,其中也要感谢孙志海大哥对我的帮助 !!
可以说使用这种方法还是比较简易的,但是,似乎仍没解决我一开头说道的问题,即这种方式仅仅是提升了程序的效率,但依然需要在UI线程中更新界面,这里也可以使用SurfaceVIew来进行异步的更新界面,但是这里,我想知道,在不修改android系统源码情况下,NDK的极限,即它能否直接控制View的surface,使其不通过java代码就直接把界面刷新呢?这个可能会涉及到Linux的文件权限问题,以及需要翻阅android系统源码。
望对这个方面感兴趣的朋友,能够和我一起交流,或者能够给我一些建议。我的QQ是835060947,也可以发邮件给我。