本节把贯穿本章的几种技术综合在了一起,创建和使用简单的C模块,它使用math库来计算幂值。我们将从文件Android.mk开始。注意,需要构建库(sample_lib),并输出include文件,然后在示例中使用这个库:
LOCAL_PATH := $(call my-dir) # this is our sample libraryinclude $(CLEAR_VARS)LOCAL_MODULE := sample_libLOCAL_SRC_FILES := samplelib/sample_lib.c # we need to make sure everything knows where everything isLOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/samplelibinclude $(BUILD_STATIC_LIBRARY) # sample uses the sample lib we createdinclude $(CLEAR_VARS)LOCAL_MODULE := sampleLOCAL_SRC_FILES := sample.cLOCAL_LDLIBS := -llog # We load our sample libLOCAL_STATIC_LIBRARIES := sample_libinclude $(BUILD_SHARED_LIBRARY)有一个短头文件sample_lib.h:#ifndef SAMPLE_LIB_H#define SAMPLE_LIB_Hextern 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 libdouble 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; } }); }}