本文主要讲两个实例一个是java调用native 函数的JNI。另一个是JNI调用java中的函数即java反调用

首先建立好android app端的java的全部代码

MainActivity:

package org.tonny.jni.jnitest;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends Activity {static{  System.loadLibrary("JNITest");  }  private native String GetReply(); private native void callJNIString(String s);private EditText edtName;  private Button btnShow; private Button stringButton = null;private TextView stringTextView = null; String reply;private Handler mHandler = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);reply= GetReply(); Log.d("jnitest","========================"); edtName= (EditText)this.findViewById(R.id.ed_name);stringTextView = (TextView)this.findViewById(R.id.stringtextview);btnShow= (Button)this.findViewById(R.id.btn_show); btnShow.setOnClickListener(new ClickListener());stringButton = (Button)this.findViewById(R.id.stringbutton);Log.e("jnitest","oooooooooooooooo"); stringButton.setOnClickListener(new ClickListener()); mHandler = new Handler()         {            @Override              public void handleMessage(Message msg)            {                 switch(msg.what)                {                    //整型                    case 0:                    {                    edtName.setText(reply);                          break;                    }                    //字符串                    case 1:                     {                    Log.d("jnitest","pptv=======");                         stringTextView.setText(msg.obj.toString());                        break;                     }                                                       }                                          }                             };        /*btnShow.setOnClickListener(new OnClickListener() {  public void onClick(View arg0) {  edtName.setText(reply);  }  });  */} public class ClickListener implements View.OnClickListener     {          @Override         public void onClick(View v)          {             // TODO Auto-generated method stub              switch(v.getId())            {                                 case R.id.stringbutton:                  {                     //调用JNI中的函数                Log.e("jnitest","======---------");                    callJNIString("你好A");                                  break;                 }                 case R.id.btn_show:                 {                                     //调用JNI中的函数                 Log.e("jnitest","babdbdbdbdbdbdb b");                  edtName.setText(reply);                     Log.e("jnitest","babdbdbdbdbdbdb b");                      break;                 }             }         }             }  private void callbackString(String s)     {         Message msg = new Message();          //消息类型          msg.what = 1;         //消息内容          msg.obj = s;          //发送消息         mHandler.sendMessage(msg);      }   }


private native String GetReply(); 可知这是一个本地函数。具体实现在jni中。

private native void callJNIString(String s);也是一个本地函数。不过这个函数在jni实现过程中会调用我们java端的callbackString();

strings.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <string name="app_name">JNITest</string>    <string name="action_settings">Settings</string>    <string name="hello_world">HelloWorld, JNITestActivity!</string>    <string name="btn_show">Show</string>     <string name="recvstr">接收到的整数</string>      <string name="btnstr">传给JNI一个字符A</string>       </resources>

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"     android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context=".MainActivity" >        <TextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" />    <EditText  android:id="@+id/ed_name"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_gravity="center_horizontal"  android:layout_marginLeft="5dp"  android:inputType="text" android:layout_marginRight="5dp"/> <Button  android:id="@+id/btn_show"  android:layout_width="109dp"  android:layout_height="wrap_content"  android:layout_gravity="center_horizontal"  android:text="@string/btn_show"/>  <TextView    android:id="@+id/stringtextview"           android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/recvstr" />    <Button  android:id="@+id/stringbutton"  android:layout_width="fill_parent"      android:layout_height="wrap_content" android:text="@string/btnstr"/>      </LinearLayout>

因为我是直接搭建的android 系统源码的编译环境所以我没有使用ndk工具。

进入到我们工程工作文件夹下的bin文件夹的class文件夹。拷贝到Ubuntu随便一个目录下面。我的是在home下。



这是我 class内文件

接着命令javah org.tonny.jni.jnitest.MainActivity

在class下生成两个文件org_tonny_jni_jnitest_MainActivity.h和org_tonny_jni_jnitest_MainActivity_ClickListener.h 其中org_tonny_jni_jnitest_MainActivity.h是我们想要的。

使我们的jni的头文件。

我是在android源码目录下的hardware/jni文件夹。然后将org_tonny_jni_jnitest_MainActivity.h拷贝到文件夹下。然后新建org_tonny_jni_jnitest_MainActivity.c

其中org_tonny_jni_jnitest_MainActivity.h内容:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class org_tonny_jni_jnitest_MainActivity */#ifndef _Included_org_tonny_jni_jnitest_MainActivity#define _Included_org_tonny_jni_jnitest_MainActivity#ifdef __cplusplusextern "C" {#endif/* * Class:     org_tonny_jni_jnitest_MainActivity * Method:    GetReply * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_org_tonny_jni_jnitest_MainActivity_GetReply  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
org_tonny_jni_jnitest_MainActivity.c

#include<jni.h>#include<string.h>#include <android/log.h>#include"org_tonny_jni_jnitest_MainActivity.h"//#define ALOGE printf#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))JNIEXPORT jstring JNICALL Java_org_tonny_jni_jnitest_MainActivity_GetReply  (JNIEnv *env, jobject obj){return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");  } JNIEXPORT void JNICALL Java_org_tonny_jni_jnitest_MainActivity_callJNIString  ( JNIEnv* env, jobject obj , jstring s){jclass cls = (*env)->FindClass(env, "org/tonny/jni/jnitest/MainActivity");jmethodID mid = (*env)->GetMethodID(env, cls, "callbackString", "(Ljava/lang/String;)V");if (mid == NULL)      {         LOGE("string error");         return;      }    const char *ch;ch = (*env)->GetStringUTFChars(env, s, NULL);LOGE("from java string: %s",ch);(*env)->ReleaseStringUTFChars(env, s, ch); (*env)->CallVoidMethod(env, obj, mid ,(*env)->NewStringUTF(env,"你好haha"));}  

可以看到
JNIEXPORT jstring JNICALL Java_org_tonny_jni_jnitest_MainActivity_GetReply

GetReply()真正的实现就是上面这个函数。只是返回一个hello

JNIEXPORT void JNICALL Java_org_tonny_jni_jnitest_MainActivity_callJNIString
函数中首先

jclass cls = (*env)->FindClass(env, "org/tonny/jni/jnitest/MainActivity");
找到java的mainactivity类在jni的实例,因为我们我们要调用callbackstring函数。只有先找到这个函数属于哪个类才能找到这个函数。

jmethodID mid = (*env)->GetMethodID(env, cls, "callbackString", "(Ljava/lang/String;)V");
找到这个函数的 jmethodID。

(*env)->CallVoidMethod(env, obj, mid ,(*env)->NewStringUTF(env,"你好haha"));
执行java端的callbackstring函数。

到这里主要代码已经完成。我们还需要简历一个mk文件

Android.mk

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE:= libJNITest LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hwLOCAL_SRC_FILES:= \ org_tonny_jni_jnitest_MainActivity.cLOCAL_SHARED_LIBRARIES := \libcutils libhardware libcLOCAL_MODULE_TAGS := optionalinclude $(BUILD_SHARED_LIBRARY)

LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
这是我们生成文件输出目录


这是我jni文件夹下的文件

Android.mk org_tonny_jni_jnitest_MainActivity.c org_tonny_jni_jnitest_MainActivity.h

若是你已经source和lunch过你的环境变量你可以直接mm编译我们这个jni文件。没有的话进入android源码根目录。执行下面两个命令后再回到jni目录

. build/envsetup.sh

lunch 14 这个lunch后数字跟你的编译rom有关不重要。你可以随便选一个你。


执行mm后发现生成的在out/target/product/g18ref/system/lib/hw/下。

在我们app的libs下新建armeabi文件夹然后将libJNITest.so拷贝进去

这样生成的apk就包含我们这个so文件。

打开我们的app



界面如图所示。


点击show按钮 对话框显示Hello,JNITest


点击下面按钮显示你好haha

跟我们预想一样。。。。

更多相关文章

  1. Android如何在初始化的时候获取加载的布局的宽高
  2. android-在代码中实现按下Home键的效果
  3. 【Android源码】Intent 源码分析
  4. 展讯android LEDS模块分析----各种关系
  5. android 事件传递机制 【转】
  6. APK 本地化和去广告
  7. SurfaceTexture,TextureView,GLsurfaceview的区别与联系详解
  8. Android(java)回调函数经典示例
  9. android ERROR:Unknown option '--no-crunch'

随机推荐

  1. android之RecycleView之ItemTouchHelper
  2. Android WiFi 架构总览(模块及接口)
  3. ionic build android log
  4. 播放音乐时的状态条使用
  5. Android AD Manifest
  6. Android(安卓)中的 values XML
  7. 分享:Android程序员,必备精品网站大汇总
  8. android打开关闭屏幕
  9. ionic emulate android log
  10. Android中ListVIew高度自适应,解决ScrollV