首页 > IT > it

Android NDK JNI 梳理

2023-02-15
字号:
Android NDK JNI 梳理 Java Animal
package cn.com.codingce.mediaandroid.entity;


import android.util.Log;


public class Animal {

    protected String name;
    public static int num = 0;

    protected int age;

    public Animal(String name) {
        this.name = name;
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Animal() {

    }

    public void setName(String name) {
        Log.e("Animal", "Animal: " + name);
        this.name = name;
    }

    public static void setNum(int num) {
        Animal.num = num;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public int getNum() {
        return num;
    }

    public static void eat() {
        System.out.println("staticMethodt" + "eatt" + "foodt");
    }

    public String getNameAndAge() {
        return this.name + "t" + this.age;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}
Activity
package cn.com.codingce.mediaandroid.activity.jni;

import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import cn.com.codingce.mediaandroid.R;
import cn.com.codingce.mediaandroid.entity.Animal;

public class JniActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jni);
        int num = 1;
        int i = 0;

        Animal animal = new Animal("花椒", 20);

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 80, 10, TimeUnit.SECONDS, new SynchronousQueue(true), new ThreadPoolExecutor.AbortPolicy());
        Future future;
        for (; i < num; i++) {
            int finalI = i;
            future = threadPoolExecutor.submit(() -> {
                try {
                    useJNICreateJavaObject(finalI, Thread.currentThread().getName(), animal);
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return true;
            });
            try {
                Boolean boolean1 = future.get();
                System.out.println(boolean1);
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
        }
        createUI();
    }

    protected void createUI() {
        //创建布局
        FrameLayout.LayoutParams startParams = new FrameLayout.LayoutParams(200, 120);
        startParams.gravity = Gravity.CENTER_HORIZONTAL;
        Button startButton = new Button(this);
        startButton.setTextColor(Color.BLUE);
        startButton.setText("按钮");
        startButton.setVisibility(View.VISIBLE);
        startButton.setOnClickListener(view -> Toast.makeText(JniActivity.this, "点击", Toast.LENGTH_SHORT).show());
        addContentView(startButton, startParams);
    }

    private native void useJNICreateJavaObject(int i, String threadName, Animal animal);

}
C++ jni_practice.h
//
// Created by Inke219223m on 2022/6/30.
//

#ifndef MEDIAANDROID_JNI_PRACTICE_H
#define MEDIAANDROID_JNI_PRACTICE_H


#include 
#include 
#include "LogUtils.h"
#include "../CLog.h"
#include "pthread.h"
#include "unistd.h"
#include "queue"
using namespace std;

class jni_practice {

};

extern "C"
JNIEXPORT void JNICALL Java_cn_com_codingce_mediaandroid_activity_jni_JniActivity_useJNICreateJavaObject
        (JNIEnv *, jobject, jint i, jstring thread_name, jobject inputAnimal);


//1、一般线程
//线程对象
pthread_t pthread;

void *threadDoThings(void *data) {
    LOGD("jni thread do things");
    pthread_exit(&pthread);
}

//2、线程锁
//产品队列,里面是int的队列
std::queue queueInit;
//生产者线程
pthread_t pthread_produc;
//消费者线程
pthread_t pthread_customer;
//线程锁
pthread_mutex_t mutexInit;
//条件对象
pthread_cond_t cond;

void initMutex();

void *customerThread(void *data);

void *ptoducThread(void *data);

void *threadDoThings(void *data);

#endif //MEDIAANDROID_JNI_PRACTICE_H
jni_practice.cpp
//
// Created by Inke219223m on 2022/6/30.
//


#include "jni_practice.h"

using namespace std;

extern "C"
JNIEXPORT void JNICALL
Java_cn_com_codingce_mediaandroid_activity_jni_JniActivity_useJNICreateJavaObject(JNIEnv
                                                                                  *env,
                                                                                  jobject thiz,
                                                                                  jint
                                                                                  i,
                                                                                  jstring threadName,
                                                                                  jobject inputAnimal) {
    //外层线程信息
    const char *threadNameWithC = env->GetStringUTFChars(threadName, JNI_FALSE);
    LOGE("线程Name: %s, %d", threadNameWithC, i)
    /// Java层传递对象处理 START 
    //想要获取的字段 id
    jfieldID fid;
    //字段对应的具体的值
    jstring inputJstr;

    //将 Java 的字符串转换为 Native 的字符串
    const char *str;
    //获取 Java class
    jclass inputAnimalCls = env->GetObjectClass(inputAnimal);
    //获取对应字段的 id
    fid = env->GetFieldID(inputAnimalCls, "name", "Ljava/lang/String;");
    //如果字段为 NULL ,直接退出,查找失败
    if (fid == nullptr) {
        return;
    }
    //获取字段对应的值
    inputJstr = (jstring) env->GetObjectField(inputAnimal, fid);
    str = env->GetStringUTFChars(inputJstr, nullptr);
    if (str == nullptr) {
        return;
    }
    LOGD("input Object name is %s", str);
    /// Java层传递对象处理 END 

    /// 创建对象 START 
    //获取 animal 对应的 jlcass 对象
    jclass animalClazz = env->FindClass("cn/com/codingce/mediaandroid/entity/Animal");
    //获取构造函数的 jmethodID
    jmethodID animal_constructor = env->GetMethodID(animalClazz, "",
                                                    "(Ljava/lang/String;I)V");
    jstring name = env->NewStringUTF("INKE");
    //调用构造函数创建 animal 对象
    jobject animal = env->NewObject(animalClazz, animal_constructor, name, 20);
    /// 创建对象END 

    /// 普通操作 START 
    //类中方法
    //get 方法
    jmethodID getName = env->GetMethodID(animalClazz, "getName", "()Ljava/lang/String;");
    //获取 get 方法返回的 Name
    auto jstringGetName = (jstring) env->CallObjectMethod(animal, getName);
    const char *charName = env->GetStringUTFChars(jstringGetName, JNI_FALSE);
    //__android_log_print(ANDROID_LOG_INFO, "mmm", "method = %s, msg = %s", __FUNCTION__, charName);
    LOGE("Create Object Get name: %s", charName)

    //set 方法
    //新 Name
    jstring nameMod = env->NewStringUTF("NewNameSetAchieve");
    //获取 set 方法
    jmethodID setName = env->GetMethodID(animalClazz, "setName", "(Ljava/lang/String;)V");
    env->
            CallVoidMethod(animal, setName, nameMod
    );

    //获取成员变量 name
    jfieldID jfieldIdName = env->GetFieldID(animalClazz, "name", "Ljava/lang/String;");
    //获取成员变量 name 的值
    auto jstr = (jstring) env->GetObjectField(animal, jfieldIdName);
    //jstring 转换成 char
    const char *charNameJstr = env->GetStringUTFChars(jstr, JNI_FALSE);
    LOGE("Get Object New Name: %s", charNameJstr)

    //获取成员变量
    jfieldID jfieldIdAge = env->GetFieldID(animalClazz, "age", "I");
    //获取成员变量 Age 的值
    jint jintAge = (jint)
            env->
                    GetIntField(animal, jfieldIdAge
            );
    LOGE("Get Object Age:%d", jintAge)
    /// 普通操作 END 

    /// 静态操作 START 
    //获取静态变量 num
    jfieldID jfieldIdNum = env->GetStaticFieldID(animalClazz, "num", "I");
    //获取静态变量 num 的值
    jint num = (jint)
            env->
                    GetStaticIntField(animalClazz, jfieldIdNum
            );
    cout << "获取静态变量 num 的值: " <<
         num;

    //修改静态变量 num 的值
    jint jint1 = 2000;
    env->
            SetStaticIntField(animalClazz, jfieldIdNum, jint1
    );
    //获取静态方法 eat()
    jmethodID jmethodId = env->GetStaticMethodID(animalClazz, "eat", "()V");
    //调用静态方法 eat()
    env->
            CallStaticVoidMethod(animalClazz, jmethodId
    );
    jint num1 = (jint)
            env->
                    GetStaticIntField(animalClazz, jfieldIdNum
            );
    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,
                        "env->GetStaticIntField(animalClazz, jfieldIdNum): %d", num1);
    /// 静态操作 END 

    /// 多线程 START 
    //创建线程
    pthread_create(&pthread, nullptr, threadDoThings, nullptr
    );

    //生产者消费者模型
    //初始化时,先往队列中添加10个产品
    //    for (
    //            int i = 0;
    //            i < 10; i++) {
    //        queueInit.push(i);
    //    }
    //生产者消费者
    //initMutex();
    /// 多线程 END 

    /// 资源释放 START //
    /// 引用型对象需要释放,包括 jstring, jclass, jobject, jbyteArray 等等;从作用域的角度分为两类:Global and Local References https://www.jianshu.com/p/c867e4abcb5f ///
    //jstring
    env->DeleteLocalRef(name);
    env->DeleteLocalRef(jstringGetName);
    env->DeleteLocalRef(nameMod);
    env->DeleteLocalRef(jstr);
    env->DeleteLocalRef(inputJstr);
    //jbyteArray
    //env->ReleaseByteArrayElements(imgdata, imgByte, 0);
    //jclass
    env->DeleteLocalRef(animalClazz);
    //如果你要返回 animal 则不需要释放
    env->DeleteLocalRef(animal);
    /// 资源释放 END //

}

void *ptoducThread(void *data) {
    while (queueInit.size() < 50) {
        LOGD("生产者生产一个产品")
        //操作队列前先加锁
        pthread_mutex_lock(&mutexInit);
        queueInit.push(1);
        if (queueInit.size() > 0) {
            LOGD("生产者通知消费者有产品产生,产品数量为:%d", queueInit.size());
            //有了产品通知消费者
            pthread_cond_signal(&cond);
        }
        //解锁线程
        pthread_mutex_unlock(&mutexInit);
        //休息4秒,单位是秒
        sleep(4);
    }
    pthread_exit(&pthread_produc);
}

void initMutex() {
    //初始化锁对象 对应pthread_mutex_destroy销毁锁对象
    pthread_mutex_init(&mutexInit, nullptr);
    //初始化条件变量 对应pthread_cond_destroy销毁条件变量
    pthread_cond_init(&cond, nullptr);
    //创建生产者线程,并传递参数
    pthread_create(&pthread_produc, nullptr, ptoducThread, (void *) "product");
    //创建消费者线程
    pthread_create(&pthread_customer, nullptr, customerThread, nullptr);
}

void *customerThread(void *data) {
    char *prod = (char *) data;
    LOGD("%s", prod)
    //这里用死循环,时间情况应该给一个变量来控制跳出循环
    while (1) {
        //操作队列前先加锁
        pthread_mutex_lock(&mutexInit);
        if (queueInit.size() > 0) {
            queueInit.pop();
            LOGE("消费者消费一个产品,产品数量为:%d", queueInit.size());
        } else {
            LOGE("产品消费完了,等待生产者生产......");
            //阻塞线程等待生产者的通知
            pthread_cond_wait(&cond, &mutexInit);
        }
        //解锁线程
        pthread_mutex_unlock(&mutexInit);
        //休息0.5秒,usleep单位是微妙
        usleep(500 * 1000);
    }
    pthread_exit(&pthread_customer);
}

今日热点

大家都在看