0

リクエストを作成し、サーバーから更新を受信する C スレッドがあります。更新は、JNI 呼び出しを介して Java に送信されます。私の問題は、最大 100 個のアイテムを含むプレイヤーのインベントリを受信したときに発生します (サーバーから 100 個の応答があり、この部分を変更できません)。問題が発生する場合と発生しない場合がありますが、在庫が大きいほど、この問題が発生する頻度が高くなります。

次のメッセージを除いて、logcat に例外はありません。

06-10 10:09:46.085: I/Choreographer(23815): Skipped 87 frames!  The application may be doing too much work on its main thread.

そして、私のアプリが閉じます。runOnUiThreadまた、アプリのクラッシュで UI を更新する行にコメントを付けても、それを言う必要があります。

JNI を使用して Java に戻ったときに UI スレッドにいるかどうかを確認しようとしましたがLooper.myLooper() == Looper.getMainLooper()false.

誰も同じ問題を経験しましたか? C スレッドは何らかの形でメイン スレッドに関連していますか? ありがとう

編集

サーバーから更新を受信すると、次の呼び出しが行われます。

  • Java スレッド (UI スレッドではない) から: という名前の C 関数を呼び出します。notifyAll
  • From notifyAllcall という名前の C 関数はupdate、Java で同等のものを呼び出します (以下のコードを参照)。

    void UpdateListenerWrapper::update(Update& u) {
        // Retrieve the current JNIEnv* with the cached JVM
        int status;
        JNIEnv* env;
        bool isAttached = false;
    
        status = gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2);
        if(status < 0) {
            __android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to get JNI environment");
            status = gCachedJVM->AttachCurrentThread(&env, NULL);
            if(status < 0) {
                __android_log_print(ANDROID_LOG_ERROR, "UpdateListenerWrapper", "Failed to attach current thread");
                return;
            }
            isAttached = true;
        }
    
        jmethodID update = env->GetMethodID(gClazzUpdateListenerWrapper, "update", "(J)V"); // J stands for Java long type
    
        // Call Java method update from jUpdateListener object
        env->CallVoidMethod(jUpdateListener, update, (jlong)(intptr_t)&u); // Pointer as agument, we'll build the Update object in Java
    
        if (isAttached) {
            gCachedJVM->DetachCurrentThread();
        }
    }
    

gCachedJVM->GetEnv((void **) &env, JNI_VERSION_1_2);問題はこの行にあり、おそらく GetEnv が UI スレッドのポインターを返すと思います。それが問題でしょうか?どうすればこれを修正できますか?

4

2 に答える 2

1

アプリのクラッシュは Choreographer の苦情とは無関係です。これらは、アニメーションが不足していることを示す単なる警告です。

スレッド ID を表示するモードで logcat 出力を表示する必要があります。adb logcat -v threadtimeコマンドラインからお勧めします。サーバー インタラクションの開始時にログ メッセージを配置すると、それが UI スレッドで実行されているかどうかを簡単に確認できます (スレッド ID とプロセス ID は同じです。システムでは保証されていませんが、アプリでは確実に当てはまります)。

メイン スレッドでネットワークまたはデータベース I/O を実行しないでください。時間がかかりすぎると、システムが飽きて、アプリが応答していないと判断します。

JNI を介してネイティブ コードを呼び出しても、別のスレッドに切り替わることはありません。C スレッドや Java スレッドはなく、C および Java で記述されたコードを呼び出したり呼び出したりできるスレッドだけです。

Re: 質問の更新...

GetEnv現在のスレッドのデータへのポインタを常に返します。また、CallVoidMethod常に現在のスレッドで発生します。間違っJNIEnvて渡したとしても、スレッドを「ジャンプ」しません。

GetMethodIDメソッドの数が多いクラスでは呼び出しにコストがかかる可能性があるため、 が設定されているのと同じポイントで呼び出しをキャッシュするようにしてくださいgClassUpdateListenerWrapper。VM からのスレッドのアタッチとデタッチもコストがかかる可能性があるため、避けるのが最善です。ここで Java メソッドから呼び出している場合は、定義上、既にアタッチされています。私はそれisAttachedが決して設定されていないと思います。

しかし、振付家が飢えている理由を本当に説明することはできません. C にログ メッセージを追加し、どのスレッドで何が起こっているかを把握し、 traceviewupdate()を使用して時間の経過を確認する必要があると思います。logcat -v threadtime

于 2013-06-11T00:14:05.210 に答える
0

問題の解決策を見つけましたが、それは私のアプリに固有のものです。update関数 (Java 側) では、何caseもなくbreak、更新ごとに新しいネットワーク呼び出しがトリガーされていました (UI スレッドではありません)。見つけるのは厄介ですが、あなたの時間とあなたの答えに感謝します。あなたは私がこれを解決するのを助けてくれました:)

于 2013-06-18T15:45:52.827 に答える