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;