Örnek: Demlik

Teapot örneği, samples/Teapot/ dizininin altında, NDK altında yer alır. kök dizinine ekleyin. Bu örnekte, ikonik gösterimi oluşturmak için OpenGL kitaplığı kullanılmaktadır Bursa çaydanlık. Özellikle, ndk_helper yardımcı sınıfını, oyunları ve öğeleri uygulamak için gerekli yerel yardımcı işlevlerin yerel uygulamalarla benzer uygulamalar sunar. Bu sınıf şunları sağlar:

  • NDK'ya özgü belirli davranışları işleyen bir soyutlama katmanı (GLContext)
  • Dokunma algılama gibi, NDK'da mevcut olmayan ancak kullanışlı yardımcı işlevler.
  • JNI için sarmalayıcılar, doku yükleme gibi platform özelliklerini gerektirir.

AndroidManifest.xml

Buradaki etkinlik beyanı NativeActivity değil, bunun bir alt sınıfıdır: TeapotNativeActivity.

<activity android:name="com.sample.teapot.TeapotNativeActivity"
        android:label="@string/app_name"
        android:configChanges="orientation|keyboardHidden">

Sonuç olarak, derleme sisteminin oluşturduğu paylaşılan nesne dosyasının adı libTeapotNativeActivity.so Derleme sistemi lib önekini ve .so uzantı; her ikisi de manifest dosyasının başlangıçta atadığı değerin bir parçası değildir android:value.

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

Uygulama.Mk

NativeActivity çerçeve sınıfını kullanan bir uygulama Bu sınıfı oluşturan Android API düzeyi 9'dan düşük. Daha fazla bilgi için NativeActivity sınıfı, bkz. Yerel Etkinlikler ve Uygulamalar.

APP_PLATFORM := android-9

Sonraki satır, derleme sistemine desteklenen tüm mimariler için derleme yapmasını söyler.

APP_ABI := all

Ardından, dosya derleme sistemine Kullanılacak C++ çalışma zamanı destek kitaplığı.

APP_STL := stlport_static

Java Tarafı Uygulaması

TeapotNativeActivity dosyası, GitHub'da teapots/classic-teapot/src/com/sample/teapot konumunda, NDK depo kök dizininde bulunur. Etkinlik yaşam döngüsü olaylarını işler, ShowUI() işleviyle ekranda metin gösterilecek bir pop-up pencere oluşturur ve updateFPS() işleviyle kare hızını dinamik olarak günceller. Aşağıdaki kod, uygulamanın Etkinliği'ni tam ekran, kapsamlı ve sistem gezinme çubukları içermeyen bir şekilde hazırlar. Böylece, oluşturulan çaydanlık çerçevelerinin tamamı tüm ekranda kullanılabilir. Bu nedenle, bu kod ilginizi çekebilir:

Kotlin

fun setImmersiveSticky() {
    window.decorView.systemUiVisibility = (
            View.SYSTEM_UI_FLAG_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            )
}

Java

void setImmersiveSticky() {
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
}

Yerel Tarafta Uygulama

Bu bölümde, Teapot uygulamasının C++'ta uygulanan bölümü incelenmektedir.

TeapotRenderer.h

Bu işlev çağrıları, çaydanlığın gerçek oluşturulmasını gerçekleştirir. Google Matris hesaplaması ve kamerayı yeniden konumlandırmak için ndk_helper kullanıcının dokunduğu yere göre.

ndk_helper::Mat4 mat_projection_;
ndk_helper::Mat4 mat_view_;
ndk_helper::Mat4 mat_model_;


ndk_helper::TapCamera* camera_;

TeapotNativeActivity.cpp

Aşağıdaki satırlar, yerel kaynak dosyasında ndk_helper öğesini içerir ve yardımcı sınıf adı.

#include "NDKHelper.h"

//-------------------------------------------------------------------------
//Preprocessor
//-------------------------------------------------------------------------
#define HELPER_CLASS_NAME "com/sample/helper/NDKHelper" //Class name of helper
function

ndk_helper sınıfının ilk kullanımı, EGL bağlam durumlarını (oluşturulan/kayıp) ilişkilendirme, EGL ile ilgili yaşam döngüsü Android yaşam döngüsü olayları. ndk_helper sınıfı, uygulamanın bağlamı korumasını sağlar. bilgi sağlaması gerekir. Bu yetenek, Örneğin, hedef makine döndürüldüğünde (etkinliğin yerine geri getirildiğinde veya imha edildikten sonra görünür.

ndk_helper::GLContext* gl_context_; // handles EGL-related lifecycle.

Ardından ndk_helper, dokunma kontrolü sağlar.

ndk_helper::DoubletapDetector doubletap_detector_;
ndk_helper::PinchDetector pinch_detector_;
ndk_helper::DragDetector drag_detector_;
ndk_helper::PerfMonitor monitor_;

Ayrıca kamera kontrolü de sağlar (openGL görünümü).

ndk_helper::TapCamera tap_camera_;

Uygulama daha sonra NDK'da sağlanan yerel API'lerden yararlanarak cihazın sensörlerini kullanmaya hazırlanır.

ASensorManager* sensor_manager_;
const ASensor* accelerometer_sensor_;
ASensorEventQueue* sensor_event_queue_;

Uygulama, çeşitli Android'lere yanıt olarak aşağıdaki işlevleri çağırır yaşam döngüsü olayları ve EGL bağlam durumu değişiklikleri, çeşitli işlevleri kullanarak ndk_helper tarafından Engine sınıfı aracılığıyla sağlanmıştır.

void LoadResources();
void UnloadResources();
void DrawFrame();
void TermDisplay();
void TrimMemory();
bool IsReady();

Ardından, aşağıdaki işlev kullanıcı arayüzü görüntüsünü güncellemek için Java tarafına geri çağrılıyor.

void Engine::ShowUI()
{
    JNIEnv *jni;
    app_->activity->vm->AttachCurrentThread( &jni, NULL );


    //Default class retrieval
    jclass clazz = jni->GetObjectClass( app_->activity->clazz );
    jmethodID methodID = jni->GetMethodID( clazz, "showUI", "()V" );
    jni->CallVoidMethod( app_->activity->clazz, methodID );


    app_->activity->vm->DetachCurrentThread();
    return;
}

Ardından, bu fonksiyon Java tarafına dönerek bir metin kutusu çizin yerel tarafta oluşturulan ekranın üzerine yerleştirilmiş ve çerçeve sayısı.

void Engine::UpdateFPS( float fFPS )
{
    JNIEnv *jni;
    app_->activity->vm->AttachCurrentThread( &jni, NULL );


    //Default class retrieval
    jclass clazz = jni->GetObjectClass( app_->activity->clazz );
    jmethodID methodID = jni->GetMethodID( clazz, "updateFPS", "(F)V" );
    jni->CallVoidMethod( app_->activity->clazz, methodID, fFPS );


    app_->activity->vm->DetachCurrentThread();
    return;
}

Uygulama sistem saatini alır ve oluşturucuya sağlar zaman tabanlı animasyon oluşturmak için kullanabilirsiniz. Bu bilgiler, örneğin hızın zamanın bir işlevi olarak düştüğü momentumu hesaplama.

renderer_.Update( monitor_.GetCurrentTime() );

Uygulama artık oluşturulan çerçeveyi GLcontext::Swap() işlevi aracılığıyla görüntülemek için ön arabelleğe çevirir. çevirme işlemi sırasında ortaya çıkan olası hataları da ele alır.

if( EGL_SUCCESS != gl_context_->Swap() )  // swaps
buffer.

Program, dokunma hareketi etkinliklerini tanımlı hareket dedektörüne iletir ndk_helper sınıfında. Hareket algılayıcı, çoklu dokunmayı izler iki parmak ucunu yakınlaştırma ya da uzaklaştırma gibi el hareketlerini sunar ve bu etkinliklerden herhangi biri.

if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
{
    ndk_helper::GESTURE_STATE doubleTapState =
        eng->doubletap_detector_.Detect( event );
    ndk_helper::GESTURE_STATE dragState = eng->drag_detector_.Detect( event );
    ndk_helper::GESTURE_STATE pinchState = eng->pinch_detector_.Detect( event );

    //Double tap detector has a priority over other detectors
    if( doubleTapState == ndk_helper::GESTURE_STATE_ACTION )
    {
        //Detect double tap
        eng->tap_camera_.Reset( true );
    }
    else
    {
        //Handle drag state
        if( dragState & ndk_helper::GESTURE_STATE_START )
        {
             //Otherwise, start dragging
             ndk_helper::Vec2 v;
             eng->drag_detector_.GetPointer( v );
             eng->TransformPosition( v );
             eng->tap_camera_.BeginDrag( v );
        }
        // ...else other possible drag states...

        //Handle pinch state
        if( pinchState & ndk_helper::GESTURE_STATE_START )
        {
            //Start new pinch
            ndk_helper::Vec2 v1;
            ndk_helper::Vec2 v2;
            eng->pinch_detector_.GetPointers( v1, v2 );
            eng->TransformPosition( v1 );
            eng->TransformPosition( v2 );
            eng->tap_camera_.BeginPinch( v1, v2 );
        }
        // ...else other possible pinch states...
    }
    return 1;
}

ndk_helper sınıfı, vektörel matematik kitaplığına da erişim sağlar. (vecmath.h), burada dokunma koordinatlarını dönüştürmek için kullanılacak.

void Engine::TransformPosition( ndk_helper::Vec2& vec )
{
    vec = ndk_helper::Vec2( 2.0f, 2.0f ) * vec
            / ndk_helper::Vec2( gl_context_->GetScreenWidth(),
            gl_context_->GetScreenHeight() ) - ndk_helper::Vec2( 1.f, 1.f );
}

HandleCmd() yöntemi, android_native_app_glue kitaplığını düzenleyebilirsiniz. İletilerin ne olduğuyla ilgili daha fazla android_native_app_glue.h ve diğer yorumlardaki yorumlara .c kaynak dosya.

void Engine::HandleCmd( struct android_app* app,
        int32_t cmd )
{
    Engine* eng = (Engine*) app->userData;
    switch( cmd )
    {
    case APP_CMD_SAVE_STATE:
        break;
    case APP_CMD_INIT_WINDOW:
        // The window is being shown, get it ready.
        if( app->window != NULL )
        {
            eng->InitDisplay();
            eng->DrawFrame();
        }
        break;
    case APP_CMD_TERM_WINDOW:
        // The window is being hidden or closed, clean it up.
        eng->TermDisplay();
        eng->has_focus_ = false;
        break;
    case APP_CMD_STOP:
        break;
    case APP_CMD_GAINED_FOCUS:
        eng->ResumeSensors();
        //Start animation
        eng->has_focus_ = true;
        break;
    case APP_CMD_LOST_FOCUS:
        eng->SuspendSensors();
        // Also stop animating.
        eng->has_focus_ = false;
        eng->DrawFrame();
        break;
    case APP_CMD_LOW_MEMORY:
        //Free up GL resources
        eng->TrimMemory();
        break;
    }
}

ndk_helper sınıfı, şu durumlarda APP_CMD_INIT_WINDOW öğesini yayınlar: android_app_glue sistemden onNativeWindowCreated() geri araması alır. Uygulamalar normalde EGL gibi pencere başlatma işlemleri gerçekleştirebilir başlatma. Bunu etkinlik yaşam döngüsünün dışında yaparlar çünkü etkinliği henüz hazır değil.

//Init helper functions
ndk_helper::JNIHelper::Init( state->activity, HELPER_CLASS_NAME );

state->userData = &g_engine;
state->onAppCmd = Engine::HandleCmd;
state->onInputEvent = Engine::HandleInput;