2016-11-21 15 views
2

Node.jsとsocket.ioを使用してAndroidアプリとデスクトップブラウザの両方にソーシャルアプリを作成しています。Android JNI APPが別のネイティブメソッドのCallObjectMethodの呼び出しでクラッシュする

ブラウザクライアントで問題なく動作するのはアンドロイドクライアント側です。実際にはsocket.io Javaクライアントを使用していましたが、ネイティブC++で処理したいと思います。 jniを使用して正常に私のnode.jsサーバーに接続します。 2つのエミッタコールバッククライアントは、デスクトップブラウザのjavascriptクライアントから送信されたサーバーからのメッセージを受け取ります。

問題は、私は...サーバー

env->CallObjectMethod(globalSocketObj,emit,lo,o);

にアプリのクラッシュを メッセージを送信し、この行を追加するときにアンドロイドクライアントがサーバーにメッセージを送信するときに発生します。 -crash MESSAGE-

11-21 10:10:58.417 9310-9310/com.example.nyari.advancenative E/dalvikvm: JNI ERROR (app bug): attempt to use stale local reference 0x1df00025 11-21 10:10:58.417 9310-9310/com.example.nyari.advancenative E/dalvikvm: VM aborting 11-21 10:10:58.418 9310-9310/com.example.nyari.advancenative A/libc: Fatal signal 6 (SIGABRT) at 0x0000245e (code=-6), thread 9310 (i.advancenative) 11-21 10:10:58.418 9310-9310/com.example.nyari.advancenative A/libc: Send stop signal to pid:9310 in void debuggerd_signal_handler(int, siginfo_t*, void*)


それはこのようなものは、すでに3日に私を取ったネイティブコードで行う必要があります。あなたのお手伝いをありがとう。

ネイティブコード:

//METHOD CONNECTING WITH NODE SERVER 
JNIEXPORT void JNICALL Java_com_example_nyari_advancenative_MainActivity_count 
       (JNIEnv* env, jobject obj){ 
      //LOCAL VARIABLES TO INSTANCES///////////////////////////////////////////////// 
      Main_class=env->GetObjectClass(obj);//GETTING MAINACTIVITY OBJECT 
      jstring f=env->NewStringUTF("http://192.168.43.113:8081"); 
      jstring il=env->NewStringUTF("hello"); 
      jstring ili=env->NewStringUTF("message"); 
     jclass my_socket=env->FindClass("io/socket/client/Socket");//GETTING SOCKET CLASS OF SOCKETIO 
     jclass my_IO=env->FindClass("io/socket/client/IO");//GETTING IO LOCAL CLASS 
      jobject socketObj=env->AllocObject(my_socket);//socketIO object 
      jobject my_IOobj=env->AllocObject(my_IO);//GETTING IO OBJECT FROM IO CLASS 
      //GETTING SOCKET STATIC METHOD FROM IO 
      jmethodID static_socket=env->GetStaticMethodID(my_IO,"socket","(Ljava/lang/String;)Lio/socket/client/Socket;"); 
      //GLOBAL VARIABLES INSTANCES 
      globalSocket= (jclass) env->NewGlobalRef(my_socket);//GLOBAL REFERENCE OF SOCKET CLASS 
      globalSocketObj=env->NewGlobalRef(socketObj);//GLOBAL SOCKETIO REFERENCE OBJECT 
     /// 
      //INSTANTIATING GLOBAL REFERENCE OF SOCKET OBJECT 
     globalSocketObj=env->CallObjectMethod(my_IOobj, static_socket, f); 
      //LOCAL REFERENCES VARIABLES 
      //GETTING CONNECT METHOD OF SOCKET CLASS 
      jmethodID socket_connect=env->GetMethodID(my_socket,"connect","()Lio/socket/client/Socket;"); 
      //GETTING THE RECEIVE EMMITER CLASS FROM MAINACTIVITY 
      receiveField=env->GetFieldID(Main_class,"receive","Lio/socket/emitter/Emitter$Listener;"); 
      //GETTING OBJECT FROM RECEIVEFIELD EMITTER FROM IN MAINACTIVITY 
      receiveObj=env->GetObjectField(obj,receiveField); 
      ///METHOD FROM SOCKET CLASS on FOR HELLO MESSAGE WITH SERVER 
      onReceive=env->GetMethodID(my_socket,"on","(Ljava/lang/String;Lio/socket/emitter/Emitter$Listener;)Lio/socket/emitter/Emitter;"); 
      ///////////////// 
      //GETTING CHAT EMITTER FIELD FROM MAINACTIVITY 
      receiveMessage=env->GetFieldID(Main_class,"chats","Lio/socket/emitter/Emitter$Listener;"); 
      //GETTING OBJECT FROM CHATFIELD EMITTER FROM IN MAINACTIVITY 
      receiveMessageObj=env->GetObjectField(obj,receiveMessage); 
      ///METHOD FROM SOCKET CLASS on FOR MESSAGES SENT AND RECEIVED 
      onReceiveMessage=env->GetMethodID(my_socket,"on","(Ljava/lang/String;Lio/socket/emitter/Emitter$Listener;)Lio/socket/emitter/Emitter;"); 
     //////////////////////////// 
      env->CallObjectMethod(globalSocketObj,onReceive,il,receiveObj); 
      env->CallObjectMethod(globalSocketObj,onReceiveMessage,ili,receiveMessageObj); 
     env->CallObjectMethod(globalSocketObj,socket_connect); 

      } 

    ///PROBLEMATIC METHOD USED TO SEND MESSAGE TO SERVER 
JNIEXPORT void JNICALL Java_com_example_nyari_advancenative_MainActivity_vari(JNIEnv* env, jobject obj){ 
     jstring il=env->NewStringUTF("hello");//message to be sent to the server 
     jstring ili=env->NewStringUTF("message");//for callback method in server 
     jclass ob=env->GetObjectClass(globalSocketObj); 
     jmethodID emit=env->GetMethodID(ob,"emit","(Ljava/lang/String;[Ljava/lang/Object;)Lio/socket/emitter/Emitter;"); 
     env->CallObjectMethod(globalSocketObj,emit,ili,il);//PROBLEMATIC CALL 

    } 

JAVA CODE : 


    public class MainActivity extends AppCompatActivity { 
    static{ 
    /*try{ 
     System.loadLibrary("louts"); 
    }catch(Error | Exception ignore){ 

    }*/ 
     System.loadLibrary("louts"); 
    } 
     TextView text,tex; 

     public native void connect(); 
     public native void count(); 
     public native void vari(); 
     public native Socket network(); 
    public native void send(); 
     String message; 
    Emitter.Listener receive,chats; 
    String jo= io.socket.client.Socket.EVENT_CONNECT; 
     ArrayList<String> items; 
     ArrayAdapter<String> adapter; 
     ListView list; 
     EditText texter; 
     Button button; 
     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 

      setContentView(R.layout.activity_main); 
      text=(TextView)findViewById(R.id.numb); 
      tex=(TextView)findViewById(R.id.num); 
    //LISTVIEW TO ADD MESSAGES FROM NODE SERVER 
      items=new ArrayList<String>(); 
     adapter=new ArrayAdapter<String>(getApplicationContext(),android.R.layout.simple_list_item_1,items); 

      list=(ListView)findViewById(R.id.list); 
      list.setAdapter(adapter); 
    //EDITTEXT TO GET MESSAGES 
      texter=(EditText)findViewById(R.id.texter); 
    //CONTAINS THE EMITTER CALLBACKS METHODS TO RECEIVE MESSAGES FROM NODE SERVER 
      emit(); 
    //THREAD THAT CONTAINS NATIVE METHOD count() that connects to NODE SERVER 
    Thread y=new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      count(); 
     } 
    }); 
      y.start(); 
    //BUTTON THAT MESSAGE TO NODE SERVER 
      button=(Button)findViewById(R.id.button); 
      button.setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View view) { 
        String j=null; 
        j=texter.getText().toString(); 
        JSONObject reg2=new JSONObject(); 
        try { 
         reg2.put("ki",j); 
         /*socket.emit("message",reg2);*/ 
         vari(); 
         texter.setText(""); 
        } catch (JSONException e) { 
         e.printStackTrace(); 
        } 
       } 
      }); 

     } 

     @Override 
     protected void onDestroy() { 
      super.onDestroy(); 
      connect(); 
     } 

     private void emit(){ 
      receive= new Emitter.Listener() { 
       @Override 
       public void call(Object... args) {//CALLBACK METHOD FOR HELLO MESSAGE FROM SERVER 
        final JSONObject obj = (JSONObject)args[0]; 
        MainActivity.this.runOnUiThread(new Runnable(){ 

         @Override 
         public void run() { 
          try { 
           message=obj.getString("ki"); 
           text.setText(message); 
          } catch (JSONException e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 

       } 
      }; 
      chats= new Emitter.Listener() { 
       @Override 
       public void call(Object... args) {//CALLBACK METHOD TO RECEIVE CHAT MESSAGES FROM SERVER 
        final JSONObject obj = (JSONObject)args[0]; 
        MainActivity.this.runOnUiThread(new Runnable(){ 

         @Override 
         public void run() { 
          try { 
           message=obj.getString("mess"); 
           // items.add(message); 
           adapter.add(message); 
           adapter.notifyDataSetChanged(); 
           //tex.setText(message); 
           //list.setVerticalScrollbarPosition(list.getHeight()); 
          } catch (JSONException e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 
       } 
      }; 

     } 
    } 
+1

なぜあなたは 'globalSocketObj = env-> NewGlobalRef(socketObj)後の次の行に' globalSocketObj'に新しい値を代入していますか; '? – Michael

+0

私は別のネイティブメソッドでそれを使うことができるようにしています –

+0

私の主張はなぜ 'env-> NewGlobalRef(socketObj);'を代入して、その値を 'env-> CallObjectMethod(my_IOobj、static_socket、f ); 'その次の行?どちらの値が正しいか? – Michael

答えて

1

あなたがここに何が問題のカップルを持っています

 globalSocketObj=env->NewGlobalRef(socketObj);//GLOBAL SOCKETIO REFERENCE OBJECT 
    /// 
     //INSTANTIATING GLOBAL REFERENCE OF SOCKET OBJECT 
    globalSocketObj=env->CallObjectMethod(my_IOobj, static_socket, f); 

まずあなたがsocketObjで呼ばSocketインスタンスへのグローバル参照を作成します。グローバル参照を作成するという点は、ローカル参照とは異なり、Javaに戻るときには削除されないということです。これまでのところ、Socketインスタンスをガベージコレクトしないでおくことを前提としています。

最初の問題は、すぐ次の行にglobalSocketObjの値を上書きするため、今作成したグローバル参照がlimboになります。これは、現在のメソッドから戻るとすぐにそのオブジェクトを参照することができなくなることを意味します。これは、最初はグローバル参照を作成する目的に反するものです。作成したグローバル参照を削除することはできないので、メモリリークが発生したばかりです。

2番目の潜在的な問題は、作成するオブジェクトのグローバル参照をenv->CallObjectMethod(my_IOobj, static_socket, f)で作成しないということです。つまり、現在のオブジェクトから返されたオブジェクトをもう参照できなくなります。方法。

1

私は最終的に解決策を見つけました。あなたの答えが で実際に私の目を開け、ネイティブコードからクリーナーway.ActuallyどこにあるのメモリリークアプリケーションがOutOfMemryErrorでクラッシュするので、次のようにしました。 まず、私のcppファイルで、IOソケット()オブジェクトを返すjobjectを作成してから、通常のソケットを使ってjavaファイルに をインスタンス化します。ここに私のネイティブコードである:

JNIEXPORT jオブジェクトJNICALL Java_com_example_nyari_advancenative_MainActivity_SocketIO(JNIEnvの* ENV、JCLASSのclazz)= env-> NewStringUTF( "http://192.168.43.113:8081")F { JSTRINGは、 jclass my_IO = env-> FindClass( "io/socket/client/IO"); // IOローカルクラスを取得中 jobject my_IOobj = env-> AllocObject(my_IO); // IOクラスからIOオブジェクトを取得 // GETTING (ソケット、クライアント、ソケット、クライアント);ソケット(ソケット)、ソケット(ソケット)、ソケット(ソケット)、ソケット(ソケット) return env-> CallObjectMethod(my_IOobj、static_socket、f);

} 

Javaコード:

public class MainActivity extends AppCompatActivity { 
    static{ 
     System.loadLibrary("louts"); 
    } 
     TextView text,tex; 

     public native void connect(); 
     public static native Socket SocketIO(); 
     Socket sok; 
     String message; 
    Emitter.Listener receive,chats; 
    String jo= io.socket.client.Socket.EVENT_CONNECT; 
     ArrayList<String> items; 
     ArrayAdapter<String> adapter; 
     ListView list; 
     EditText texter; 
     Button button; 
     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 

      setContentView(R.layout.activity_main); 
      text=(TextView)findViewById(R.id.numb); 
      tex=(TextView)findViewById(R.id.num); 
    //LISTVIEW TO ADD MESSAGES FROM NODE SERVER 
      items=new ArrayList<String>(); 
     adapter=new ArrayAdapter<String>(getApplicationContext(),android.R.layout.simple_list_item_1,items); 

      list=(ListView)findViewById(R.id.list); 
      list.setAdapter(adapter); 
    //EDITTEXT TO GET MESSAGES 
      texter=(EditText)findViewById(R.id.texter); 
    //CONTAINS THE EMITTER CALLBACKS METHODS TO RECEIVE MESSAGES FROM NODE SERVER 
      emit(); 
    //THREAD THAT CONTAINS NATIVE METHOD count() that connects to NODE SERVER 
    Thread y=new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      sok=SocketIO(); 
      sok.on("hello", receive); 
      sok.on("message",chats); 
      sok.connect(); 
     } 
    }); 
      y.start(); 
    //BUTTON THAT MESSAGE TO NODE SERVER 
      button=(Button)findViewById(R.id.button); 
      button.setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View view) { 
        String j=null; 
        j=texter.getText().toString(); 
        JSONObject reg2=new JSONObject(); 
        try { 
         reg2.put("ki",j); 
         sok.emit("message",reg2); 
         texter.setText(""); 
        } catch (JSONException e) { 
         e.printStackTrace(); 
        } 
       } 
      }); 

     } 

     @Override 
     protected void onDestroy() { 
      super.onDestroy(); 
      connect(); 
     } 

     private void emit(){ 
      receive= new Emitter.Listener() { 
       @Override 
       public void call(Object... args) {//CALLBACK METHOD FOR HELLO MESSAGE FROM SERVER 
        final JSONObject obj = (JSONObject)args[0]; 
        MainActivity.this.runOnUiThread(new Runnable(){ 

         @Override 
         public void run() { 
          try { 
           message=obj.getString("ki"); 
           text.setText(message); 
          } catch (JSONException e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 

       } 
      }; 
      chats= new Emitter.Listener() { 
       @Override 
       public void call(Object... args) {//CALLBACK METHOD TO RECEIVE CHAT MESSAGES FROM SERVER 
        final JSONObject obj = (JSONObject)args[0]; 
        MainActivity.this.runOnUiThread(new Runnable(){ 

         @Override 
         public void run() { 
          try { 
           message=obj.getString("mess"); 
           // items.add(message); 
           adapter.add(message); 
           adapter.notifyDataSetChanged(); 
           //tex.setText(message); 
           //list.setVerticalScrollbarPosition(list.getHeight()); 
          } catch (JSONException e) { 
           e.printStackTrace(); 
          } 
         } 
        }); 
       } 
      }; 

     } 
    } 
Hope it helps some one with the same problem 
関連する問題