你的位置:首页 > 操作系统

[操作系统]android ndk开发(二)实现一个官方demo

实现了一个官方的demo:bitmap-plasma(水波纹)

源代码就在samples文件夹下,可以自己去找。

界面:

建立项目的步骤和配置环境不明白的可以去看:http://www.cnblogs.com/jycboy/p/5393727.html

一、activity代码:

package example.user.plasmatest;import android.os.Bundle;import android.app.Activity;import android.os.Bundle;import android.content.Context;import android.view.View;import android.graphics.Bitmap;import android.graphics.Canvas;import android.view.Display;import android.view.WindowManager;public class MainActivity extends Activity{  /** Called when the activity is first created. */  @Override  public void onCreate(Bundle savedInstanceState)  {    super.onCreate(savedInstanceState);    Display display = getWindowManager().getDefaultDisplay();    setContentView(new PlasmaView(this, display.getWidth(), display.getHeight()));  }  /* load our native library */  static {    System.loadLibrary("plasma");  }}class PlasmaView extends View {  private Bitmap mBitmap;  private long mStartTime;  /* implementend by libplasma.so */  private static native void renderPlasma(Bitmap bitmap, long time_ms);  public PlasmaView(Context context, int width, int height) {    super(context);    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);    mStartTime = System.currentTimeMillis();  }  @Override  protected void onDraw(Canvas canvas) {    //canvas.drawColor(0xFFCCCCCC);    renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime);    canvas.drawBitmap(mBitmap, 0, 0, null);    // force a redraw, with a different time-based pattern.    invalidate();  }}

 make project下,利用javah创建jni目录、.h头文件

在jni目录下创建c代码:

plasma.c:

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *   http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "example_user_plasmatest_PlasmaView.h"#include <jni.h>#include <time.h>#include <android/log.h>#include <android/bitmap.h>#include <stdio.h>#include <stdlib.h>#include <math.h>#define LOG_TAG  "libplasma"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)/* Set to 1 to enable debug log traces. */#define DEBUG 0/* Set to 1 to optimize memory stores when generating plasma. */#define OPTIMIZE_WRITES 1/* Return current time in milliseconds */static double now_ms(void){  struct timeval tv;  gettimeofday(&tv, NULL);  return tv.tv_sec*1000. + tv.tv_usec/1000.;}/* We're going to perform computations for every pixel of the target * bitmap. floating-point operations are very slow on ARMv5, and not * too bad on ARMv7 with the exception of trigonometric functions. * * For better performance on all platforms, we're going to use fixed-point * arithmetic and all kinds of tricks */typedef int32_t Fixed;#define FIXED_BITS      16#define FIXED_ONE      (1 << FIXED_BITS)#define FIXED_AVERAGE(x,y)  (((x) + (y)) >> 1)#define FIXED_FROM_INT(x)  ((x) << FIXED_BITS)#define FIXED_TO_INT(x)   ((x) >> FIXED_BITS)#define FIXED_FROM_FLOAT(x) ((Fixed)((x)*FIXED_ONE))#define FIXED_TO_FLOAT(x)  ((x)/(1.*FIXED_ONE))#define FIXED_MUL(x,y)    (((int64_t)(x) * (y)) >> FIXED_BITS)#define FIXED_DIV(x,y)    (((int64_t)(x) * FIXED_ONE) / (y))#define FIXED_DIV2(x)    ((x) >> 1)#define FIXED_AVERAGE(x,y)  (((x) + (y)) >> 1)#define FIXED_FRAC(x)    ((x) & ((1 << FIXED_BITS)-1))#define FIXED_TRUNC(x)    ((x) & ~((1 << FIXED_BITS)-1))#define FIXED_FROM_INT_FLOAT(x,f)  (Fixed)((x)*(FIXED_ONE*(f)))typedef int32_t Angle;#define ANGLE_BITS       9#if ANGLE_BITS < 8# error ANGLE_BITS must be at least 8#endif#define ANGLE_2PI        (1 << ANGLE_BITS)#define ANGLE_PI        (1 << (ANGLE_BITS-1))#define ANGLE_PI2        (1 << (ANGLE_BITS-2))#define ANGLE_PI4        (1 << (ANGLE_BITS-3))#define ANGLE_FROM_FLOAT(x)  (Angle)((x)*ANGLE_PI/M_PI)#define ANGLE_TO_FLOAT(x)   ((x)*M_PI/ANGLE_PI)#if ANGLE_BITS <= FIXED_BITS# define ANGLE_FROM_FIXED(x)   (Angle)((x) >> (FIXED_BITS - ANGLE_BITS))# define ANGLE_TO_FIXED(x)    (Fixed)((x) << (FIXED_BITS - ANGLE_BITS))#else# define ANGLE_FROM_FIXED(x)   (Angle)((x) << (ANGLE_BITS - FIXED_BITS))# define ANGLE_TO_FIXED(x)    (Fixed)((x) >> (ANGLE_BITS - FIXED_BITS))#endifstatic Fixed angle_sin_tab[ANGLE_2PI+1];static void init_angles(void){  int nn;  for (nn = 0; nn < ANGLE_2PI+1; nn++) {    double radians = nn*M_PI/ANGLE_PI;    angle_sin_tab[nn] = FIXED_FROM_FLOAT(sin(radians));  }}static __inline__ Fixed angle_sin( Angle a ){  return angle_sin_tab[(uint32_t)a & (ANGLE_2PI-1)];}static __inline__ Fixed angle_cos( Angle a ){  return angle_sin(a + ANGLE_PI2);}static __inline__ Fixed fixed_sin( Fixed f ){  return angle_sin(ANGLE_FROM_FIXED(f));}static __inline__ Fixed fixed_cos( Fixed f ){  return angle_cos(ANGLE_FROM_FIXED(f));}/* Color palette used for rendering the plasma */#define PALETTE_BITS  8#define PALETTE_SIZE  (1 << PALETTE_BITS)#if PALETTE_BITS > FIXED_BITS# error PALETTE_BITS must be smaller than FIXED_BITS#endifstatic uint16_t palette[PALETTE_SIZE];static uint16_t make565(int red, int green, int blue){  return (uint16_t)( ((red  << 8) & 0xf800) |            ((green << 2) & 0x03e0) |            ((blue >> 3) & 0x001f) );}static void init_palette(void){  int nn, mm = 0;  /* fun with colors */  for (nn = 0; nn < PALETTE_SIZE/4; nn++) {    int jj = (nn-mm)*4*255/PALETTE_SIZE;    palette[nn] = make565(255, jj, 255-jj);  }  for ( mm = nn; nn < PALETTE_SIZE/2; nn++ ) {    int jj = (nn-mm)*4*255/PALETTE_SIZE;    palette[nn] = make565(255-jj, 255, jj);  }  for ( mm = nn; nn < PALETTE_SIZE*3/4; nn++ ) {    int jj = (nn-mm)*4*255/PALETTE_SIZE;    palette[nn] = make565(0, 255-jj, 255);  }  for ( mm = nn; nn < PALETTE_SIZE; nn++ ) {    int jj = (nn-mm)*4*255/PALETTE_SIZE;    palette[nn] = make565(jj, 0, 255);  }}static __inline__ uint16_t palette_from_fixed( Fixed x ){  if (x < 0) x = -x;  if (x >= FIXED_ONE) x = FIXED_ONE-1;  int idx = FIXED_FRAC(x) >> (FIXED_BITS - PALETTE_BITS);  return palette[idx & (PALETTE_SIZE-1)];}/* Angles expressed as fixed point radians */static void init_tables(void){  init_palette();  init_angles();}static void fill_plasma( AndroidBitmapInfo* info, void* pixels, double t ){  Fixed yt1 = FIXED_FROM_FLOAT(t/1230.);  Fixed yt2 = yt1;  Fixed xt10 = FIXED_FROM_FLOAT(t/3000.);  Fixed xt20 = xt10;#define YT1_INCR  FIXED_FROM_FLOAT(1/100.)#define YT2_INCR  FIXED_FROM_FLOAT(1/163.)  int yy;  for (yy = 0; yy < info->height; yy++) {    uint16_t* line = (uint16_t*)pixels;    Fixed   base = fixed_sin(yt1) + fixed_sin(yt2);    Fixed   xt1 = xt10;    Fixed   xt2 = xt20;    yt1 += YT1_INCR;    yt2 += YT2_INCR;#define XT1_INCR FIXED_FROM_FLOAT(1/173.)#define XT2_INCR FIXED_FROM_FLOAT(1/242.)#if OPTIMIZE_WRITES    /* optimize memory writes by generating one aligned 32-bit store     * for every pair of pixels.     */    uint16_t* line_end = line + info->width;    if (line < line_end) {      if (((uint32_t)(uintptr_t)line & 3) != 0) {        Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2);        xt1 += XT1_INCR;        xt2 += XT2_INCR;        line[0] = palette_from_fixed(ii >> 2);        line++;      }      while (line + 2 <= line_end) {        Fixed i1 = base + fixed_sin(xt1) + fixed_sin(xt2);        xt1 += XT1_INCR;        xt2 += XT2_INCR;        Fixed i2 = base + fixed_sin(xt1) + fixed_sin(xt2);        xt1 += XT1_INCR;        xt2 += XT2_INCR;        uint32_t pixel = ((uint32_t)palette_from_fixed(i1 >> 2) << 16) |                 (uint32_t)palette_from_fixed(i2 >> 2);        ((uint32_t*)line)[0] = pixel;        line += 2;      }      if (line < line_end) {        Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2);        line[0] = palette_from_fixed(ii >> 2);        line++;      }    }#else /* !OPTIMIZE_WRITES */    int xx;    for (xx = 0; xx < info->width; xx++) {      Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2);      xt1 += XT1_INCR;      xt2 += XT2_INCR;      line[xx] = palette_from_fixed(ii / 4);    }#endif /* !OPTIMIZE_WRITES */    // go to next line    pixels = (char*)pixels + info->stride;  }}/* simple stats management */typedef struct {  double renderTime;  double frameTime;} FrameStats;#define MAX_FRAME_STATS 200#define MAX_PERIOD_MS  1500typedef struct {  double firstTime;  double lastTime;  double frameTime;  int     firstFrame;  int     numFrames;  FrameStats frames[ MAX_FRAME_STATS ];} Stats;static voidstats_init( Stats* s ){  s->lastTime = now_ms();  s->firstTime = 0.;  s->firstFrame = 0;  s->numFrames = 0;}static voidstats_startFrame( Stats* s ){  s->frameTime = now_ms();}static voidstats_endFrame( Stats* s ){  double now = now_ms();  double renderTime = now - s->frameTime;  double frameTime = now - s->lastTime;  int nn;  if (now - s->firstTime >= MAX_PERIOD_MS) {    if (s->numFrames > 0) {      double minRender, maxRender, avgRender;      double minFrame, maxFrame, avgFrame;      int count;      nn = s->firstFrame;      minRender = maxRender = avgRender = s->frames[nn].renderTime;      minFrame = maxFrame = avgFrame = s->frames[nn].frameTime;      for (count = s->numFrames; count > 0; count-- ) {        nn += 1;        if (nn >= MAX_FRAME_STATS)          nn -= MAX_FRAME_STATS;        double render = s->frames[nn].renderTime;        if (render < minRender) minRender = render;        if (render > maxRender) maxRender = render;        double frame = s->frames[nn].frameTime;        if (frame < minFrame) minFrame = frame;        if (frame > maxFrame) maxFrame = frame;        avgRender += render;        avgFrame += frame;      }      avgRender /= s->numFrames;      avgFrame /= s->numFrames;      LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) "             "render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n",         1000./avgFrame, 1000./maxFrame, 1000./minFrame,         avgRender, minRender, maxRender);    }    s->numFrames = 0;    s->firstFrame = 0;    s->firstTime = now;  }  nn = s->firstFrame + s->numFrames;  if (nn >= MAX_FRAME_STATS)    nn -= MAX_FRAME_STATS;  s->frames[nn].renderTime = renderTime;  s->frames[nn].frameTime = frameTime;  if (s->numFrames < MAX_FRAME_STATS) {    s->numFrames += 1;  } else {    s->firstFrame += 1;    if (s->firstFrame >= MAX_FRAME_STATS)      s->firstFrame -= MAX_FRAME_STATS;  }  s->lastTime = now;}JNIEXPORT void JNICALL Java_example_user_plasmatest_PlasmaView_renderPlasma(JNIEnv * env, jobject obj, jobject bitmap, jlong time_ms){AndroidBitmapInfo info;void*       pixels;int        ret;static Stats    stats;static int     init;if (!init) {init_tables();stats_init(&stats);init = 1;}if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);return;}if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {LOGE("Bitmap format is not RGB_565 !");return;}if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);}stats_startFrame(&stats);/* Now fill the values with a nice little plasma */fill_plasma(&info, pixels, time_ms );AndroidBitmap_unlockPixels(env, bitmap);stats_endFrame(&stats);}//// Created by user on 2016/4/14.//

修改build.gradle文件: 添加ndk{......}
defaultConfig {
applicationId "example.user.plasmatest"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
ndk{
moduleName "plasma"
ldLibs "log"
ldLibs "jnigraphics"//新增
}
}
修改Android.mk文件:
添加:LOCAL_LDLIBS := -llog -ljnigraphics
这是我的Android.mk:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := plasmaLOCAL_LDFLAGS := -Wl,--build-idLOCAL_LDLIBS := \  -llog \  -ljnigraphics \LOCAL_SRC_FILES := \  D:\as_workspace\NDKDemo2\plasmatest\src\main\jni\plasma.c \  D:\as_workspace\NDKDemo2\plasmatest\src\main\jni\util.c \LOCAL_C_INCLUDES += D:\as_workspace\NDKDemo2\plasmatest\src\main\jniLOCAL_C_INCLUDES += D:\as_workspace\NDKDemo2\plasmatest\src\debug\jniinclude $(BUILD_SHARED_LIBRARY)


运行即可。。。
遇到的问题:

问题一:Error:(383) undefined reference to `__android_log_print':

1 修改 Android.mk 文件相关:

1
LOCAL_LDLIBS := -llog

 

2 如果使用 android studio,需要修改 gradle 脚本:

1
2
3
4
5
6
7
8
android {
defaultConfig {
ndk {
moduleName "serial_port"
ldLibs "log"
}
}
}

也就是添加了一句:ldLibs "log"

问题二:Error:(377) undefined reference to `AndroidBitmap_getInfo'

修改Android.mk文件:
添加:LOCAL_LDLIBS := -llog -ljnigraphics

修改 gradle 脚本如下:

ndk {  moduleName "webcam"  ldLibs "log"  ldLibs "jnigraphics"}

其实这句的意思就是增加动态链接库 jnigraphics ,这样就搞定了呢,是的,就是这样。

 

问题三:找不到appcompatActivity

 这时候你的activity应该继承的是appcompatActivity,

  解决方法一:修改成继承Activity就可以

 解决方法二:javah -d jni -classpath D:\ide\android-sdk\platforms\android-22\android.jar;D:\ide\android-sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug

 在javah命令中加上android-support-v7-appcompat.jar这个的路径,在安装目录下,一级级找就可以。