2016-11-21 508 views
2

我正在为使用Node.js和socket.io的android应用和桌面浏览器创建社交应用。Android JNI应用从另一种本地方法调用CallObjectMethod

在浏览器客户端上,每件事情都很好,问题在于android客户端。实际上,我使用了socket.io java客户端,我希望在native C++中这样做。我已成功调用socket.io java客户端类使用jni并成功连接到我的node.js服务器。两个发射器回调客户端从桌面浏览器JavaScript客户端接收来自服务器的消息。

的问题时,Android客户端将消息发送到服务器时,我此行发送 信息添加到服务器

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*)


它有这个东西已经采取了我三天本地代码来完成。感谢您的帮助。

本地代码:

//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,因此您刚创建的全局引用现在处于空白状态。这意味着,只要从当前方法返回,您就无法再引用Socket对象,这种方式首先会破坏创建全局引用的目的。而且由于你不能删除你创建的全局引用,你只能让自己陷入内存泄漏。

第二个潜在的问题是您不会为您使用env->CallObjectMethod(my_IOobj, static_socket, f)创建的对象创建全局引用,这意味着您将无法再从当前返回的对象中引用该对象方法。

1

我终于找到了solution.I首先要谢谢迈克尔,因为你的答案 竟睁开眼睛,使我从本地代码不同的清洁剂连接way.Actually你在哪里正确的,但有很多内存泄漏和应用程序崩溃与OutOfMemryError所以我这样做了以下方式 首先在我的cpp文件中创建一个jobject,返回一个IO.socket()对象,然后在我的java文件中使用常规套接字实例化 。这是我的本机代码:

JNIEXPORT jobject JNICALL Java_com_example_nyari_advancenative_MainActivity_SocketIO(JNIEnv的* ENV,JCLASS clazz所){ 的jstring F = env-> NewStringUTF( “http://192.168.43.113:8081”);我们可以通过下面的例子来说明如何使用IO类来访问数据库:io/socket/client/IO; //获取IO本地类; ; SOCKET静态方法来自IO jmethodID static_socket = env-> GetStaticMethodID(my_IO,“socket”,“(Ljava/lang/String;)Lio/socket/client/Socket;”); 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