关于 android 的JNI的java 调用 C和 C 调用JAVA(2)

本文主要讲两个实例一个是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;
	@Override
	protected 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 __cplusplus
extern "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)/hw
	
LOCAL_SRC_FILES:= \
	 org_tonny_jni_jnitest_MainActivity.c

LOCAL_SHARED_LIBRARIES := \
	libcutils libhardware libc

LOCAL_MODULE_TAGS := optional

include $(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

跟我们预想一样。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九霄的爸爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值