簡體   English   中英

使用C ++中的NDK更新Android UI

[英]Using NDK from C++ updating Android UI

我的問題與這篇文章直接相關: https : //groups.google.com/forum/#!topic/android-ndk/291sBdkITyI

基本上,我有一個用C ++編寫的應用程序,它是使用NDK和基本的Android(活動)編譯的。 我有一個textview(在Java中),當c ++方面發生某些事情(例如,狀態更改)時,需要對其進行更新。 我想從C ++調用Java並在狀態更改時更新textview。

在上面的鏈接中,他們使用的代碼是(可能是偽代碼):

public class Example extends Activity{    

    Handler handler = new Handler() {

         @Override
         public void handleMessage(Message msg) {
             this.currentDownloadField.setText(""+ msg.what);
         }

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // whatever
    }   

    public static void sendMessage(int  id){ 
         handler.sendEmptyMessage(id); // just the what() is filled with the id
    }
}

從C ++調用將是

void sendMessage(char* buffer, int bufferlen) {
    JNIEnv *env = NULL;
    jmethodID mid = NULL;
    jbyteArray message;

    jint res = (jjvm->AttachCurrentThread(&jjvm, &env, NULL));

    if (res >= 0) {
        message = (*env)->NewByteArray(env, bufferlen);
        (*env)->SetByteArrayRegion(env, message, 0, bufferlen, (const jbyte *) ((BYTE*) buffer));
        mid = (*env)->GetStaticMethodID(env, jcls, "sendMessage", "([B)V");

        // Mid <= 0 ? Not found : OK
        if (mid > 0) {
        (*env)->CallStaticVoidMethod(env, jcls, mid, message);
        }
    }
}

問題是在靜態函數的活動中使用“處理程序”不起作用(因為它不是靜態的)。 如果它是靜態的,那么如何引用“ this.currentDownloadField”?

我也嘗試過僅從C ++調用公共函數

public void update(String message) {
    Log.i("logging", "Hit here")
    mMyTextField.setText(message);
}

當C ++調用Java函數“ update”時,命中日志(在logcat中),但是textview不更新。 也許這是線程的問題,但我不知道如何正確更新文本字段。

另一個選擇是輪詢並讓Java調用C ++來讀取變量(狀態),但是這很乏味且不是良好的編程習慣。

有什么建議可以解決這個問題嗎?

提前致謝。

沒錯,您必須從UI線程調用mMyTextField.setText() Android Java類提供了多種實現方法,例如View.post()Handler.post()Handler.sendMessage()Activity.runOnUiThread() 這些方法都不是靜態的 ,它們都需要一個活動的對象才能工作。

有多種方法可以解決此問題。 對代碼的最小更改可能如下所示:

public class Example extends Activity {

    private static Handler staticHandler;
    private TextView currentDownloadField;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                this.currentDownloadField.setText(""+ msg.what);
            }
        }
        staticHandler = handler;
        setContentView(R.layout.main_view);
        currentDownloadField = (TextView)findViewById(R.id.download_field);
    }

    @Override
    protected void onDestroy() {
        staticHandler = null;
    }

    public static void sendMessage(int id) {
        staticHandler.sendEmptyMessage(id); // just the what() is filled with the id
    }
}

在上面的代碼中,為簡潔起見,跳過了錯誤檢查。

或者,您可以將對活動(或處理程序或downloadFiled)的引用傳遞給C庫,而不是調用CallStaticVoidMethod() ,而是使用對象全局引用並使用CallVoidMethod(env, jactivityObj, mid, message)

PS我只是想知道,如果將jbyteArray (在Java中為byte[] )發送給需要int的回調方法,那么您希望系統如何工作?

更新上面的簡單代碼受Handler Leak約束,因此,如果要在生產中重用它,請在Handler周圍包括一個靜態內部類包裝器

調用JNI C / C ++函數時,您將擁有其方法被調用的對象以及JNIEnv:

JNIEXPORT void JNICALL Java_com_xxx_Yyy_myfunc(JNIEnv *, jobject);

您可以調用該對象的非靜態方法。

如果您的C ++代碼沒有提供在其中傳遞多余的void *的方法,則只需將內容存儲到靜態變量中,並確保僅在UI線程上使用它即可。 或者至少總是來自同一線程。

PS,您可以嘗試通過線程本地存儲等添加線程安全性。但是您不能控制線程的生命周期。 由於不清楚的原因,您可能會得到晦澀的錯誤。 因此,如果您只需要兩個線程,則IMO具有兩個(JNIEnv *,jobject)對象對的結構或數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM