Android 中间件,hello-jni dame 代码分析

简单介绍一下JNI:

JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

android  jni 开发 使用NDK 开发工具。

参考:

http://blog.csdn.net/acanoe/article/details/8613714

转载请标明出处:

http://blog.csdn.net/ACanoe

这篇博文简单分析一下jni 开发所依赖的文件和程序简单说明:

下面是 hello-jni 目录结构

|-- AndroidManifest.xml
|-- default.properties
|-- jni
|   |-- Android.mk # Android.mk  类似于Linux 下的Makefile
|   `-- hello-jni.c
|-- libs
|   `-- armeabi
|       |-- gdb.setup
|       |-- gdbserver
|       `-- libhello-jni.so
|-- obj
|   `-- local
|       `-- armeabi
|           |-- libhello-jni.so # 这个是编译后得到的.so 文件
|           `-- objs-debug
|               `-- hello-jni
|                   |-- hello-jni.o
|                   `-- hello-jni.o.d
|-- res
|   `-- values
|       `-- strings.xml
|-- src
|   `-- com
|       `-- example
|           `-- hellojni
|               `-- HelloJni.java
`-- tests
    |-- AndroidManifest.xml
    |-- default.properties
    `-- src
        `-- com
            `-- example
                `-- HelloJni
                    `-- HelloJniTest.java

主要代码为:jni/hello-jni.c   和 src/com/example/hellojni/HelloJni.java

HelloJni.java 代码:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.hellojni;

import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;


public class HelloJni extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        /* Create a TextView and set its content.
         * the text is retrieved by calling a native
         * function.
         */
        TextView  tv = new TextView(this);
        tv.setText( stringFromJNI() );
        setContentView(tv);
    }

    /* A native method that is implemented by the
     * 'hello-jni' native library, which is packaged
     * with this application.
     */
    public native String  stringFromJNI();       // 函数 stringFromJNI() 调用 lib 中 hello-jni.c 中的 
						 // Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,jobject thiz )
// 函数名解析为: java 为语言 ,com_example_hellojni 为包目录,
HelloJni也就是类名 , stringFormJNI,是你在 .java 中调用的真正函数名。
/* This is another native method declaration that is *not* * implemented by 'hello-jni'. This is simply to show that * you can declare as many native methods in your Java code * as you want, their implementation is searched in the * currently loaded native libraries only the first time * you call them. * * Trying to call this function will result in a * java.lang.UnsatisfiedLinkError exception ! */ public native String unimplementedStringFromJNI(); /* this is used to load the 'hello-jni' library on application * startup. The library has already been unpacked into * /data/data/com.example.HelloJni/lib/libhello-jni.so at * installation time by the package manager. */ static { System.loadLibrary("hello-jni"); // 声明使用lib 的文件名, 去掉 libhello-jni.so 中的lib 和 .so 字符后就是程序所要声明的lib 名称 }}



hello-jni.c  代码为:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include <string.h>
#include <jni.h>

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
 */
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}


jni/Android.mk 代码为:

# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni	#编译后的Module
LOCAL_SRC_FILES := hello-jni.c  #要编译的源码文件

include $(BUILD_SHARED_LIBRARY)


你可以尝试修改函数名,以及替换字符串。来验证.so 调用正确与否。

为了验证 hello-jni.c 中大函数是引用包目录,现在我新建一个android test 项目使用MainActivity默认的类名称,使用button 来获得libhello-jni.so 中的字符串。

 新包目录结构为 button  com.example.button  

其中MainActivity.java 代码为:

package com.example.button;



import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {
	TextView mtxtPeri;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mtxtPeri = (TextView)findViewById(R.id.txtPeri);

		//下面的代码用于为按钮注册一个监听
        findViewById(R.id.button).setOnClickListener(new OnClickListener() {
        //下面的代码用于处理按钮点击后的事件
            	public void onClick(View v) {
            	//下面的代码用于使背景变色    
                
                mtxtPeri.setText( stringFromJNI() );
             //   setContentView(mtxtPeri);
            	findViewById(R.id.button).setBackgroundColor(Color.BLUE);
		Log.v("Test_fclose", stringFromJNI());      // Log cat 打印操作
            }
        });
	}
	
    public native String  stringFromJNI();

    /* This is another native method declaration that is *not*
     * implemented by 'hello-jni'. This is simply to show that
     * you can declare as many native methods in your Java code
     * as you want, their implementation is searched in the
     * currently loaded native libraries only the first time
     * you call them.
     *
     * Trying to call this function will result in a
     * java.lang.UnsatisfiedLinkError exception !
     */
    public native String  unimplementedStringFromJNI();

    /* this is used to load the 'hello-jni' library on application
     * startup. The library has already been unpacked into
     * /data/data/com.example.HelloJni/lib/libhello-jni.so at
     * installation time by the package manager.
     */
    static {
        System.loadLibrary("hello-jni");
    }

}


XML 文件修改
res/layout/activity_main.xml 代码为:

<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"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/txtPeri"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
     />
    
	<Button android:id="@+id/button"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"

 />

</RelativeLayout>
这时编译运行的时候就会报错,应为对应的libs 对应的 包目录不对。 所以需要重新编译修改.so 文件。

只需要将原有的hello-jni.c 的函数名修改为:

Java_com_example_button_MainActivity_stringFromJNI()

就像我前面所说的: Java 为语言, com.example.button 为包目录, MainActivity 为class 名,stringFromJNI 为class 类中实际调用的接口。(这一部分纯属我个人理解)

1.然后重新编译,将生成的.so 文件替换原有的就行。

2. run

点击按钮能获得我们改写的字符串就代表验证成功。

代码分析中若有出错,还望多多指正。


你可能感兴趣的:(Android 中间件,hello-jni dame 代码分析)