• Android-JNI编程-图文解析


           要想阅读并调试下文源码,首先要确保你的NDK环境是ok的;
           编译环境:win7+Eclipse+ADT+SDK+NDK;基本用最新的就ok。
           说明下,下文代码就是一个简单的个人jni实现【挺简单的个实现,只是完整实现出来之间经历了好多曲折,记录下呵】;
           不是现成的例子,是自己学习了下jni对Java、c/c++的映射关系之后的一个实现,如有不妥请指正。
           先看一下开始到结束的流程: 【1-10步】
           1.建立普通Android工程:
     
            2.垒一个傻瓜布局,用来显示jni回传信息:

         3.手工创建jni目录-【工程根目录下】

          4.然后在jni目录下建立native实现的源文件(**.c/**.cpp);

          5.进行逻辑实现[见下文];

          6.生成相应的Android.mk文件:

          7.对Android.mk文件属性进行确认:尤其是注意源文件后缀名!!!!

          8.确认无误后通过 debug模式进行动态库(*.so)的编译、生成:此步骤处于Eclipse的C/C++视图下

            而后生成相应的*.so动态库,自动嵌入到libs/armeabi目录下;
            其中obj目录下生成的是中间文件*.o;其中控制台输出的日志我还不清楚什么意思,有明白的请明示:


          9.编译无误后,切换到Eclipse的Java视图下,进行普通的Android项目运行操作:

              10.正常操作后的效果演示:   
                日志效果:

              真机实测效果:
         

             好啦, 到现在为止,效果已经看的差不多了,那么接下来就是上代码了··
         1. 傻瓜布局文件:

    <RelativeLayout 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" >
    
      <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下面将显示来自jni端的返回--" />
    
        <TextView
            android:id="@+id/show_jni_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/textView2"
            android:layout_below="@+id/textView2"
            android:layout_marginTop="77dp"
            android:text="此处即将显示来自jni的消息--" />
    
        <Button
            android:id="@+id/jni_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/textView2"
            android:layout_marginTop="17dp"
            android:text="点击此btn调用jni方法" />
    
    </RelativeLayout>

              2.activity实现:很简单-点击按钮显示jni回传信息

    package com.quanjin.jni;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class QuanjinJniActivity extends Activity implements OnClickListener {
    
    	private static final String TAG = "MainActivity";
    	private Button jniButton;
    	private TextView showJniText;
    
    	//加载共享库
    	static {
    		System.loadLibrary("quanjin_jni");//去掉共享库的前缀lib/后缀so
    	}
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_quanjin_jni);
    		Log.d(TAG, show());//log查看返回值。
    		Log.d("info_out", show());
    		
    		jniButton = (Button) findViewById(R.id.jni_btn);
    		showJniText = (TextView) findViewById(R.id.show_jni_text);
    		jniButton.setOnClickListener(this);
    	}
    
    	//声明native方法  在jni中实现。
    	private native String show();
    	private void callback() {
    		Log.d(TAG, " call back from native");
    		//故意抛出一个异常留给jni处理,如果处理,java层就不会抛;不处理,java层就会抛出异常;
    		throw new NullPointerException();
    	}
    	
    	@Override
    	public void onClick(View v) {
    		if(v.getId() == R.id.jni_btn) {
    			//将jni返回值显示在特定控件上。
    			showJniText.setText(show());
    		}
    	}
    
    }
    

             3.最重要大部分: native部分的实现-- 看你用什么语言了C/C++都可以;只是C用JNIEve时要先解引用;

    #include <string.h>
    #include <jni.h>
    
    jstring
    Java_com_quanjin_jni_QuanjinJniActivity_show( JNIEnv* env, jobject thiz)
    {
    	//通过此方法得到传入对象的类型信息
    	//此时的对象,就是调用native方法的那个对象
    	jclass jcls = (*env)->GetObjectClass(env, thiz);
    	//根据类信息得到callback方法的methodID
    	jmethodID jmId = (*env)->GetMethodID(env, jcls, "callback", "()V");
    	//调用callback方法
    	(*env)->CallVoidMethod(env, thiz, jmId);
    	//Java层的callback方法中抛出异常, 故此时 jni调用必然出现异常, 必须检查并处理异常;否则异常将会抛给Java层的callback方法;
    	//而此时的Java层的callback也未捕获异常, 故:此时进程死掉;
    	if((*env)->ExceptionCheck(env))
    	{
    		(*env)->ExceptionDescribe(env);
    		(*env)->ExceptionClear(env);//清除异常;如果注销此句,异常将被抛回至Java层,即Java层中将在log中显示异常情况;
    	}
    	//处理异常后响应Java层的调用
    	return (*env)->NewStringUTF(env, "show message from jni by quanjin!"
    			"
     ABCDEFGHIGKLMNOPQRSTUVWXYZ 
     "
    			"when you have watch the above messages, congratulations, you got it!");
    	//中文貌似乱码了-- 大爷的    \n 中文: 这是来自本人写的jni内容, 当你看到这些话的时候呢, 恭喜你, jni调用成功啦
    }
    

              说明下: 如果没接触过的同志们,可能看起来云里雾里的,阅读前先熟悉下jni的函数签名规则比较好【稍后博客继续探讨】;
       详情见代码注释。主要用Java反射,通过获得由jni传进来的对象引用,然后相继获得其他信息;
       至于拓展开来,其他业务逻辑该怎么去展开,之后博客再写一下,今天的内容主要是开个头吧~~~
              嗯 , 基本先说这么多吧; 百闻不如一试试,完整的项目就不贴出来了, 如果有需要进一步研究的请留言附邮箱地址。

             建议:
         1. 我之前一直在项目过程中抽空研究C++,其实过程中既增强了自己对面向对象的理解,又可以更深入的研究Android框架源码(Java+C++);
         感觉都是差不多的,了解基础性内容不难,若真想做到融会贯通,短时间内不太容易,慢慢深入慢慢研究吧;
         2. Android源码是个好东西哦~ 无论是哪个版本的,有空的时候阅读一下,感觉真的很爽;就像你在拜读一本武林秘籍一样,你也不知道该怎么读,但是当你开始着迷的时候便一发不可收拾,太棒了!

  • 相关阅读:
    连接池的实现 redis例子
    XSS的防御
    element-UI使用中:el-input type为textarea时@change无法触发?
    textarea高度自适应(转载)
    友盟统计单页面应用vue
    axios formData提交数据 && axios设置charset无效???
    解锁技能:sass + node-sass多页面应用编译(转载)
    css3新单位vw、vh、vmin、vmax的使用详解(转载)
    移动端bug集合
    Python3之Memcache使用
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3339647.html
Copyright © 2020-2023  润新知