本节把贯穿本章的几种技术综合在了一起,创建和使用简单的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;
}
});
}
}