本节把贯穿本章的几种技术综合在了一起,创建和使用简单的C模块,它使用math库来计算幂值。我们将从文件Android.mk开始。注意,需要构建库(sample_lib),并输出include文件,然后在示例中使用这个库:
LOCAL_PATH := $(call my-dir) # this is our sample library include $(CLEAR_VARS) LOCAL_MODULE := sample_lib LOCAL_SRC_FILES := samplelib/sample_lib.c # we need to make sure everything knows where everything is LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/samplelib include $(BUILD_STATIC_LIBRARY) # sample uses the sample lib we created include $(CLEAR_VARS) LOCAL_MODULE := sample LOCAL_SRC_FILES := sample.c LOCAL_LDLIBS := -llog # We load our sample lib LOCAL_STATIC_LIBRARIES := sample_lib include $(BUILD_SHARED_LIBRARY) 有一个短头文件sample_lib.h : #ifndef SAMPLE_LIB_H #define SAMPLE_LIB_H extern double calculatePower(double x, double y); #endif
函数sample_lib.c的源代码如下所示:
#include \"sample_lib.h\" // we include the math lib #include \"math.h\" // we use the math lib double calculatePower(double x, double y) { return pow(x, y); }
以下sample.c文件把sample_lib库和Java代码结合起来:
// we include the sample_lib #include \"sample_lib.h\" #include <jni.h> #include <android/log.h> #define LOGINFO(x...) __android_log_print(ANDROID_LOG_INFO,\"SampleJNI\",x) jdouble Java_com_oreilly_demo_android_pa_ndkdemo_SampleActivityWithNativeMethods_calculatePower( JNIEnv* env, jobject thisobject, jdouble x, jdouble y) { LOGINFO(\"Sample Info Log Output\"); // we call sample-lib\'s calculate method return calculatePower(x, y); }
本例Activity所使用的布局如下所示:
<?xml version=\"1.0\" encoding=\"utf-8\"?> <LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" android:orientation=\"vertical\" android:layout_ android:layout_ > <EditText android:id=\"@+id/x\" android:layout_ android:layout_ android:paddingTop=\"5dp\" android:paddingBottom=\"5dp\" android:textColor=\"#000\" android:hint=\"X Value\" /> <EditText android:id=\"@+id/y\" android:layout_ android:layout_ android:paddingTop=\"5dp\" android:paddingBottom=\"5dp\" android:textColor=\"#000\" android:hint=\"Y Value\" /> <Button android:id=\"@+id/calculate\" android:layout_ android:layout_ android:paddingTop=\"5dp\" android:paddingBottom=\"5dp\" android:text=\"Calculate X^Y\" /> </LinearLayout>
接下来我们修改的SampleActivityWithNativeMethods activity,它使用了新的库文件,加载该示例库并声明calculatePower方法。当单击calculate按钮时,接收两个编辑文本框中获取的数值(如果文本为空或不是数值形式,默认使用2),并把这两个数值传递给calculatePower方法。然后,返回的double类型的计算结果会弹出,作为Toast的一部分:
package com.oreilly.demo.android.pa.ndkdemo; import com.oreilly.demo.android.pa.ndkdemo.R; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class SampleActivityWithNativeMethods extends Activity { static { System.loadLibrary(\"sample\"); // load our sample lib } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample); setupview; } // sample lib native method public native double calculatePower(double x, double y); private void setupview { findViewById(R.id.calculate).setOnClickListener( new View.OnClickListener { public void onClick(View v) { String answer = \"\"; double x = 2; double y = 2; String sx = ((EditText) findViewById(R.id.x)).getText.toString; String sy = ((EditText) findViewById(R.id.y)).getText.toString; if(sx == null) { answer = \"X defaults to 2n\"; } else { try { x = Double.parseDouble(sx); } catch (Exception e) { answer = \"X is not a number, defaulting to 2n\"; x = 2; } } if(sy == null) { answer += \"Y defaults to 2n\"; } else { try { y = Double.parseDouble(sy); } catch (Exception e) { answer = \"Y is not a number, defaulting to 2n\"; y = 2; } } double z = calculatePower(x, y); answer += x+\"^\"+y+\" = \"+z; Toast.makeText(SampleActivityWithNativeMethods.this, answer, Toast.LENGTH_SHORT).show; } }); } }