Paso de parámetros en funciones con Android NDK [Parte 5]

Curso de Wireshark

Wireshark, antes conocido como Ethereal, es un software de análisis de protocolos que se basa en las librerías Pcap y que, como he dicho anteriormente, se utiliza comunmente como herramienta para realizar un análisis de redes y aplicaciones en red. Wireshark soporta una gran cantidad de protocolos (más de 450), como ICMP, HTTP, TCP, DNS, y un largo etcétera.

Comenzar ahora

tutorial android ndk parametros funciones geeky theory portada

¡Hola! Bienvenidos al tutorial número 5 de la serie sobre Android NDK. Si no se me ocurre nada más, este será el penúltimo ya que tenía pensado hacer 6. Pienso que es una buena cantidad para este tipo de tutoriales, pero bueno, ya veremos. También podéis sugerir algún ejercicio si tenéis interés en hacerlo y veré si puedo publicar algo de lo que pedís.

Hoy vamos a hacer un pequeño ejercicio creando varias funciones a las cuales les vamos a pasar parámetros y nos van a devolver un resultado. No es un ejemplo útil para la "vida real" pero sí os dará pie a empezar con cosas no tan simples.

Métodos

  • suma(int numero1, int numero2): devuelve la suma de los dos números introducidos.
  • resta(int numero1, int numero2): devuelve la resta de los dos números introducidos.

Son métodos muy sencillos, pero para ver cómo se pasan parámetros y se devuelven, nos sobra.

Pasos a seguir

1. Creamos un nuevo proyecto y lo dejamos así:

tutorial android ndk parametros funciones geeky theory

Todo lo demás lo dejamos por defecto, tal cual viene.

2. Modificar el fichero activity_main.xml.

Este archivo contiene la información de lo que se va a mostrar por pantalla. Únicamente necesito 2 TextView para mostrar lo que devuelve cada método. Dejamos uno encima de otro así:

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.geekytheory.funcionesparam.MainActivity" >

    <TextView
        android:id="@+id/textViewMetodo1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/textViewMetodo2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textViewMetodo1"
        android:layout_below="@+id/textViewMetodo1" />

</RelativeLayout>

 3. Declarar los métodos nativos en la clase MainActivity.

Ya vimos en los tutoriales anteriores (más específicamente en el tutorial 4) cómo realizar este proceso. En este caso, quedará algo así:

public class MainActivity extends Activity {
    
    static {
        System.loadLibrary("funcionesparam");
    }
    
    native int suma(int numero1, int numero2);
    native int resta(int numero1, int numero2);

    TextView textoMetodo1, textoMetodo2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }

}

 4. Modificar el método onCreate, en el cual haremos la llamada a los métodos.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textoMetodo1 = (TextView) findViewById(R.id.textViewMetodo1);
        textoMetodo2 = (TextView) findViewById(R.id.textViewMetodo2);
        
        textoMetodo1.setText("Suma: " + suma(1, 5));
        textoMetodo2.setText("Resta: " + resta(1, 5));
    }

5. Creamos la carpeta jni en la raíz del proyecto.

tutorial android ndk parametros funciones geeky theory carpeta jni

6. Creamos el makefile con el nombre "Android.mk" dentro de la carpeta jni y añadimos el siguiente contenido:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= funcionesparam
LOCAL_SRC_FILES:= funcionesparam.c
include $(BUILD_SHARED_LIBRARY)

7. Crear el fichero de cabecera con JAVAH.

Siguiendo el paso 3.3 del tutorial anterior, hacemos lo siguiente:

  • Navegamos al directorio del proyecto:
cd /home/mario/workspace/Funcionesparam/
  • Para los de Windows:
javah -jni -classpath <RUTA-A-TU-SDK>/platforms/android-19/android.jar;bin/classes/ -d jni/ com.geekytheory.funcionesparam.MainActivity
  •  Para los de Linux:
javah -jni -classpath <RUTA-A-TU-SDK>/platforms/android-19/android.jar:bin/classes/ -d jni/ com.geekytheory.funcionesparam.MainActivity

En mi caso sería:

javah -jni -classpath /home/mario/.android-sdk/platforms/android-19/android.jar:bin/classes/ -d jni/ com.geekytheory.funcionesparam.MainActivity

Se nos va a generar un archivo dentro de la carpeta jni, como vemos en la siguiente imagen:

tutorial android ndk parametros funciones geeky theory carpeta jni archivo cabecera

8. Crear el archivo en C con el código de las funciones.

Para ello, igual que en el tutorial anterior, hacemos una copia del archivo que acabamos de generar y la renombramos a funcionesparam.c.

Vamos a borrar todo el contenido innecesario para dejarlo así:

#include <jni.h>
#include <com_geekytheory_funcionesparam_MainActivity.h>

jint JNICALL Java_com_geekytheory_funcionesparam_MainActivity_suma
  (JNIEnv *, jobject, jint, jint);

jint JNICALL Java_com_geekytheory_funcionesparam_MainActivity_resta
  (JNIEnv *, jobject, jint, jint);

 9. Programar las funciones.

Ahora mismo, tenemos el fichero funcionesparam.c con el código de arriba. Tenemos que añadir los parámetros a estas funciones:

  • JNIEnv * -> JNIEnv * env.
  • jobject -> jobject obj.
  • jint -> jint numero.

También abriremos corchetes para añadir código y haremos return de las operaciones. Ahora estamos en este punto:

#include <jni.h>
#include <com_geekytheory_funcionesparam_MainActivity.h>

jint JNICALL Java_com_geekytheory_funcionesparam_MainActivity_suma
  (JNIEnv *env, jobject obj, jint numero1, jint numero2) {
    return numero1 + numero2;
}

jint JNICALL Java_com_geekytheory_funcionesparam_MainActivity_resta
  (JNIEnv *env, jobject obj, jint numero1, jint numero2) {
    return numero1 - numero2;
}

 10. Compilar el código.

Haciendo uso de la herramienta ndk-build haremos la compilación del proyecto y ya lo tendremos listo para ejecutar la aplicación.

cd /home/mario/workspace/Funcionesparam/
ndk-build

11. Ejecutar la aplicación.

Tras ejecutar la aplicación, ya sea en emulador o en dispositivo físico, obtenemos lo siguiente:

android ndk hola mundo primera aplicación 8 res  

Con esto acabo este tutorial. En el próximo haré una comparación de eficiencia entre programar con Java o de forma nativa. Si tenéis alguna sugerencia o pregunta, ya sabéis, dejad un comentario.

¡Un saludo!

¿Quieres seguir aprendiendo?