Android Studio上NDK编程步骤与演示

简介: Android Studio上NDK编程步骤与演示在AndroidStudio(AS)上搞NDK编程首先要下载与安装NDK,搞好了这步之后。只需要以下几步配置与操作就可以轻松开始NDK编程与运行。

Android Studio上NDK编程步骤与演示

在AndroidStudio(AS)上搞NDK编程首先要下载与安装NDK,搞好了这步之后。只需要以下几步配置与操作就可以轻松开始NDK编程与运行。

新建一个纯Android项目(不包含C++支持)

在新项目中创建一个新Java文件为BitmapProcessor.java, 定义两个本地方法,代码实现如下:

package com.gloomyfish.ndkdemo;

import android.graphics.Bitmap;

/**
 * Created by jia20003 on 2017/5/18.
 */

public class BitmapProcessor {

    static {
        System.loadLibrary("BitmapProcessor");
    }

    public native void gray(Bitmap bm);

    public native void inverse(Bitmap bm);

}

编译含有本地方法的Java文件和产生.h的C++文件

首先新建一个bat脚本文件javahrun.bat然后写入如下内容

set JAVA_HOME="C:\Program Files\Java\jdk1.8.0_92"
set path=%JAVA_HOME%\bin;%path%
set classpath=.;%classpath%;%JAVA_HOME%\lib;C:\Users\Administrator\AppData\Local\Android\sdk\platforms\android-24\android.jar
javah com.gloomyfish.ndkdemo.BitmapProcessor

首先用javac BitmapProcessor.java这句替换脚本文件中的最后一句,然后保存该文件到项目所在的目录下app\src\main\java\com\gloomyfish\ndkdemo位置之后,通过cmd命令行执行javahrun.bat即可。

成功执行的话会生成一个.class文件在相同目录下面
这里写图片描述

然后退到目录app\src\main\java\下面,同时把bat文件修改为之前的脚本,直接执行就会生成.h的头文件,在app\src\main目录下新建jni与jniLIB两个目录文件夹之后,把.h头文件copy到jni文件夹中,这个时候在AS看到的目录结构应该如下:
这里写图片描述

新建一个C++源文件命名为BitmapProcessor.cpp, 实现头文件中定义与声明的两个本地方法即可,注意这个可以在VS2015中完成。设置一下头文件即可,如果你不知道该include多少个或者哪个,直接把目录%disk_dir%Android\android-ndk-r13b\platforms\android-24\arch-arm\usr\include下的全部添加到VS2015的include配置中即可。这样写完程序,确保没有C++的语法错误,然后copy到AS中。

编译含有C++的NDK项目

首先要设置一下NDK的路径, 右键项目打开Module Settings
这里写图片描述
然后设置好NDK路径即可。

其次,在app对应的build.gradle文件添加如下一段脚本
这里写图片描述

最后在gradle.properties文件中添加上一句话
android.useDeprecatedNdk=true
如果不加的话,编译就会又错误出现。

然后【build】->【clean build】, 【rebuild】
就编译好啦!

使用so库与编写java相关代码

首先把编译生成的app\build\intermediates\ndk\debug\lib下面的文件全部copy到之前建好的jniLIB里面即可。然后完成Java部分代码编写,实现用户交互与UI响应操作。
这里我通过JNI实现了在C++层对Bitmap对象的灰度化操作与颜色取反操作然后返回结果。运行效果如下:
这里写图片描述
这里写图片描述

相关Java与C++代码实现

MainActivity.java

package com.gloomyfish.ndkdemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button grayBtn = (Button)this.findViewById(R.id.gray_btn);
        Button invertBtn = (Button)this.findViewById(R.id.invert_btn);
        grayBtn.setOnClickListener(this);
        invertBtn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.gray_btn:
                convert2Gray();
                break;
            case R.id.invert_btn:
                invertImage();
                break;
            default:
                break;
        }
    }

    private void invertImage() {
        Bitmap bm = BitmapFactory.decodeResource(this.getResources(), R.drawable.test);
        BitmapProcessor processor = new BitmapProcessor();
        processor.inverse(bm);
        ImageView iv = (ImageView)this.findViewById(R.id.imageView_001);
        iv.setImageBitmap(bm);
    }

    private void convert2Gray() {
        Bitmap bm = BitmapFactory.decodeResource(this.getResources(), R.drawable.test);
        BitmapProcessor processor = new BitmapProcessor();
        processor.gray(bm);
        ImageView iv = (ImageView)this.findViewById(R.id.imageView_001);
        iv.setImageBitmap(bm);
    }
}

BitmapProcessor.cpp

//
// Created by gloomy fish on 2017/5/18.
//
#include<android/bitmap.h>
#include<android/log.h>
#include<com_gloomyfish_ndkdemo_BitmapProcessor.h>

#ifndef eprintf
#define eprintf(...) __android_log_print(ANDROID_LOG_ERROR,"@",__VA_ARGS__)
#endif

#define RGBA_A(p) (((p) & 0xFF000000) >> 24)
#define RGBA_R(p) (((p) & 0x00FF0000) >> 16)
#define RGBA_G(p) (((p) & 0x0000FF00) >>  8)
#define RGBA_B(p)  ((p) & 0x000000FF)
#define MAKE_RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))

JNIEXPORT void JNICALL Java_com_gloomyfish_ndkdemo_BitmapProcessor_gray
  (JNIEnv *env, jobject clazz, jobject bmpObj) {
    AndroidBitmapInfo bmpInfo={0};
    if(AndroidBitmap_getInfo(env,bmpObj,&bmpInfo)<0)
    {
        eprintf("invalid bitmap\n");
        return;
    }

    void * dataFromBmp = NULL;
    int res = AndroidBitmap_lockPixels(env, bmpObj, &dataFromBmp);
    if(dataFromBmp == NULL)
    {
        eprintf("could not retrieve pixels from bitmap\n");
        return;
    }
    eprintf("Effect: %dx%d, %d\n", bmpInfo.width, bmpInfo.height, bmpInfo.format);
    int x = 0;
    int y = 0;
    int width = bmpInfo.width;
    int height = bmpInfo.height;
    for(y=0; y<height; y++) {
        for(x=0; x<width; x++) {
            int a = 0, r = 0, g = 0, b = 0;
            void *pixel = NULL;
            pixel = ((uint32_t *)dataFromBmp) + y * width + x;
            uint32_t v = *(uint32_t *)pixel;
            a = RGBA_A(v);
            r = RGBA_R(v);
            g = RGBA_G(v);
            b = RGBA_B(v);

            // Grayscale
            int gray = (r * 38 + g * 75 + b * 15) >> 7;

            // Write the pixel back
            *((uint32_t *)pixel) = MAKE_RGBA(gray, gray, gray, a);
        }
    }

    AndroidBitmap_unlockPixels(env, bmpObj);
}

JNIEXPORT void JNICALL Java_com_gloomyfish_ndkdemo_BitmapProcessor_inverse
    (JNIEnv *env, jobject clazz, jobject bmpObj) {
AndroidBitmapInfo bmpInfo={0};
    if(AndroidBitmap_getInfo(env,bmpObj,&bmpInfo)<0)
    {
        eprintf("invalid bitmap\n");
        return;
    }

    void * dataFromBmp = NULL;
    int res = AndroidBitmap_lockPixels(env, bmpObj, &dataFromBmp);
    if(dataFromBmp == NULL)
    {
        eprintf("could not retrieve pixels from bitmap\n");
        return;
    }
    eprintf("Effect: %dx%d, %d\n", bmpInfo.width, bmpInfo.height, bmpInfo.format);
    int x = 0;
    int y = 0;
    int width = bmpInfo.width;
    int height = bmpInfo.height;
    for(y=0; y<height; y++) {
        for(x=0; x<width; x++) {
            int a = 0, r = 0, g = 0, b = 0;
            void *pixel = NULL;
            pixel = ((uint32_t *)dataFromBmp) + y * width + x;
            uint32_t v = *(uint32_t *)pixel;
            a = RGBA_A(v);
            r = RGBA_R(v);
            g = RGBA_G(v);
            b = RGBA_B(v);

            // 取反操作
            r = 255 - r;
            g = 255 - g;
            b = 255 - b;

            // Write the pixel back
            *((uint32_t *)pixel) = MAKE_RGBA(r, g, b, a);
        }
    }

    AndroidBitmap_unlockPixels(env, bmpObj);
}

PS:
我之所有把图像处理相关的都整到C++这一层来,是因为Android Studio 上用Java干这个事情真TMD太慢了,唯一C++才是唯一出路,想做AR或者图像处理与视频分析必须要学会此技能!

目录
相关文章
|
4月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
309 1
|
2月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
2月前
|
Java Unix Linux
Android Studio中Terminal运行./gradlew clean build提示错误信息
遇到 `./gradlew clean build`命令执行出错时,首先应检查错误信息的具体内容,这通常会指向问题的根源。从权限、环境配置、依赖下载、版本兼容性到项目配置本身,逐一排查并应用相应的解决措施。记住,保持耐心,逐步解决问题,往往复杂问题都是由简单原因引起的。
312 2
|
3月前
|
Dart 开发工具 Android开发
在 Android 系统上搭建 Flutter 环境的具体步骤是什么?
在 Android 系统上搭建 Flutter 环境的具体步骤是什么?
|
3月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
159 1
|
3月前
|
XML IDE 开发工具
🔧Android Studio高级技巧大公开!效率翻倍,编码不再枯燥无味!🛠️
【9月更文挑战第11天】在软件开发领域,Android Studio凭借其强大的功能成为Android开发者的首选IDE。本文将揭示一些提升开发效率的高级技巧,包括自定义代码模板、重构工具、高级调试技巧及多模块架构。通过对比传统方法,这些技巧不仅能简化编码流程,还能显著提高生产力。例如,自定义模板可一键插入常用代码块;重构工具能智能分析并安全执行代码更改;高级调试技巧如条件断点有助于快速定位问题;多模块架构则提升了大型项目的可维护性和团队协作效率。掌握这些技巧,将使你的开发之旅更加高效与愉悦。
72 5
|
4月前
|
编解码 Android开发
【Android Studio】使用UI工具绘制,ConstraintLayout 限制性布局,快速上手
本文介绍了Android Studio中使用ConstraintLayout布局的方法,通过创建布局文件、设置控件约束等步骤,快速上手UI设计,并提供了一个TV Launcher界面布局的绘制示例。
65 1
|
4月前
|
Android开发
Android Studio: 解决Gradle sync failed 错误
本文介绍了解决Android Studio中出现的Gradle同步失败错误的步骤,包括从`gradle-wrapper.properties`文件中获取Gradle的下载链接,手动下载Gradle压缩包,并替换默认下载路径中的临时文件,然后重新触发Android Studio的"Try Again"来完成同步。
1607 0
Android Studio: 解决Gradle sync failed 错误
|
4月前
|
Android开发 iOS开发 C#
Xamarin.Forms:从零开始的快速入门指南——打造你的首个跨平台移动应用,轻松学会用C#和XAML构建iOS与Android通用界面的每一个步骤
【8月更文挑战第31天】Xamarin.Forms 是一个强大的框架,让开发者通过单一共享代码库构建跨平台移动应用,支持 iOS、Android 和 Windows。使用 C# 和 XAML,它简化了多平台开发流程并保持一致的用户体验。本指南通过创建一个简单的 “HelloXamarin” 应用演示了 Xamarin.Forms 的基本功能和工作原理。
99 0
|
Java Android开发 C++
【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )(二)
【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )(二)
570 0
【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )(二)