Beispiel: native Aktivität

Das Beispiel für native Aktivitäten befindet sich unter der NDK-Beispielstamm, im Ordner native-activity Das ist ein sehr einfaches Beispiel für eine ohne Java-Quellcode. Falls keine Java-Quelle vorhanden ist, Der Java-Compiler erstellt weiterhin einen ausführbaren Stub, den die virtuelle Maschine ausführen kann. Der Stub dient als Wrapper für das eigentliche native Programm, das sich im .so befindet. -Datei.

Die App selbst rendert eine Farbe auf dem gesamten Bildschirm und und ändert dann die Farbe teilweise als Reaktion auf erkannte Bewegungen.

AndroidManifest.xml

Eine App mit ausschließlich nativem Code darf kein Android-API-Level unter 9 angeben. Framework-Klasse NativeActivity

<uses-sdk android:minSdkVersion="9" />

In der folgenden Zeile wird android:hasCode als false deklariert, da diese App nur nativer Code – ohne Java.

<application android:label="@string/app_name"
android:hasCode="false">

In der nächsten Zeile wird die Klasse NativeActivity deklariert.

<activity android:name="android.app.NativeActivity"

Schließlich gibt das Manifest android:value als Namen der gemeinsam genutzten Bibliothek an, die erstellt, abzüglich der anfänglichen lib- und der .so-Erweiterung. Dieser Wert muss mit den Namen von LOCAL_MODULE auf Android.mk.

<meta-data android:name="android.app.lib_name"
        android:value="native-activity" />

Android.Mk

Diese Datei enthält zuerst den Namen der gemeinsam genutzten Bibliothek, die generiert werden soll.

LOCAL_MODULE    := native-activity

Als Nächstes wird der Name der nativen Quellcodedatei deklariert.

LOCAL_SRC_FILES := main.c

Als Nächstes werden die externen Bibliotheken aufgelistet, die das Build-System zum Erstellen der Binärdatei verwenden kann. Die -l (verlinken) vor jedem Bibliotheksnamen.

  • log ist eine Logging-Bibliothek.
  • android umfasst die standardmäßigen Android-Support-APIs für NDK. Weitere Informationen zu Informationen zu den von Android und vom NDK unterstützten APIs finden Sie unter Android NDK Native APIs
  • EGL entspricht dem plattformspezifischen Teil der Grafik-API.
  • GLESv1_CM entspricht OpenGL ES, der Version von OpenGL für Android. Diese Bibliothek hängt von EGL ab.

Für jede Bibliothek:

  • Der tatsächliche Dateiname beginnt mit lib und endet mit .so. Zum Beispiel der tatsächliche Dateiname für die Die log-Bibliothek ist liblog.so.
  • Die Bibliothek befindet sich im folgenden Verzeichnis, dem NDK-Stammverzeichnis: <ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/
LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM

Die nächste Zeile enthält den Namen der statischen Bibliothek, android_native_app_glue, der vom App zur Verwaltung von NativeActivity-Lebenszyklus-Ereignissen und Eingabe per Berührung

LOCAL_STATIC_LIBRARIES := android_native_app_glue

Mit der letzten Zeile wird das Build-System angewiesen, diese statische Bibliothek zu erstellen. Das Skript ndk-build platziert die erstellte Bibliothek. (libandroid_native_app_glue.a) in das Verzeichnis obj die während des Build-Prozesses generiert werden. Weitere Informationen zu android_native_app_glue finden Sie im android_native_app_glue.h-Header und der entsprechenden .cQuelldatei.

$(call import-module,android/native_app_glue)

Weitere Informationen zur Datei Android.mk finden Sie unter Android.mk

haupt.c

Diese Datei enthält im Wesentlichen das gesamte Programm.

Die folgendenIncludes entsprechen den Bibliotheken, sowohl gemeinsam genutzten als auch statischen, in Android.mk aufgezählt.

#include <EGL/egl.h>
#include <GLES/gl.h>


#include <android/sensor.h>
#include <android/log.h>
#include <android_native_app_glue>

Die Bibliothek android_native_app_glue ruft die folgende Funktion auf: und übergeben ihm eine vordefinierte Statusstruktur. Er dient auch als Wrapper, vereinfacht die Verarbeitung von NativeActivity-Callbacks.

void android_main(struct android_app* state) {

Als Nächstes verarbeitet das Programm Ereignisse, die von der Glue Library in die Warteschlange gestellt werden. Das Ereignis folgt der Zustandsstruktur.

struct engine engine;



// Suppress link-time optimization that removes unreferenced code
// to make sure glue isn't stripped.
app_dummy();


memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;

Die Anwendung bereitet sich auf die Überwachung der Sensoren vor. Dabei werden die APIs in sensor.h.

    engine.sensorManager = ASensorManager_getInstance();
    engine.accelerometerSensor =
                    ASensorManager_getDefaultSensor(engine.sensorManager,
                        ASENSOR_TYPE_ACCELEROMETER);
    engine.sensorEventQueue =
                    ASensorManager_createEventQueue(engine.sensorManager,
                        state->looper, LOOPER_ID_USER, NULL, NULL);

Als Nächstes beginnt eine Schleife, in der die Anwendung das System nach Meldungen (Sensorereignisse). Er sendet Nachrichten an android_native_app_glue, die prüft, ob sie übereinstimmen alle onAppCmd-Ereignisse, die in android_main definiert sind. Wenn ein Übereinstimmung vorliegt, wird die Nachricht zur Ausführung an den Handler gesendet.

while (1) {
        // Read all pending events.
        int ident;
        int events;
        struct android_poll_source* source;


        // If not animating, we will block forever waiting for events.
        // If animating, we loop until all events are read, then continue
        // to draw the next frame of animation.
        while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL,
                &events,
                (void**)&source)) >= 0) {


            // Process this event.
            if (source != NULL) {
                source->process(state, source);
            }


            // If a sensor has data, process it now.
            if (ident == LOOPER_ID_USER) {
                if (engine.accelerometerSensor != NULL) {
                    ASensorEvent event;
                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
                            &event, 1) > 0) {
                        LOGI("accelerometer: x=%f y=%f z=%f",
                                event.acceleration.x, event.acceleration.y,
                                event.acceleration.z);
                    }
                }
            }


        // Check if we are exiting.
        if (state->destroyRequested != 0) {
            engine_term_display(&engine);
            return;
        }
    }

Sobald die Warteschlange leer ist und das Programm die Abfrageschleife beendet, wird das Ereignis das OpenGL-Programm aufruft, um den Bildschirm zu zeichnen.

    if (engine.animating) {
        // Done with events; draw next animation frame.
        engine.state.angle += .01f;
        if (engine.state.angle > 1) {
            engine.state.angle = 0;
        }


        // Drawing is throttled to the screen update rate, so there
        // is no need to do timing here.
        engine_draw_frame(&engine);
    }
}