Android Studio NDK Novice Tutorials (5)--java Object Transfer and change

Source: Internet
Author: User
Tags sprintf string back

Overview

In this paper, the main object between Java and C + + is passed and evaluated. This includes passing Java objects, returning Java objects, altering Java objects, and performance comparisons.

Data conversion completed by jnienv

Java objects exist in a JVM virtual machine, and C + + is executed out of the JVM, assuming access to and use of objects in Java in C + +. Will certainly use the JNIEnv bridge. In fact, the following code is very easy to see, this way of access and the reflection in Java is very similar.

Here a simple Java object is defined for the following test:

 PackageCom.example.wastrel.hellojni;/** * Created by Wastrel on 2016/8/24. * * Public  class Bean {    PrivateString msg;Private intwhat; Public Bean(String msg,intWhat) { This. msg=msg; This. what=what; } PublicStringgetmsg() {returnMsg } Public void setmsg(String msg) { This. msg = msg; } Public int Getwhat() {returnwhat; } Public void Setwhat(intWhat) { This. what = what; }@Override     PublicStringtoString() {return "MSG:"+msg+"; What: "+what; }}
Creates a Java object from C + + and returns
    //Java中的native方法声明    publicnativenewBean(String msg,int what);
implementation of the method in//c++Jniexport J Object jnicall java_com_example_wastrel_hellojni_hellojni_newbean (JNIEnv *env, J object obj, jstring msg,jint what) {    //Find class firstJ class bean_clz=env-findclass("com/example/wastrel/ Hellojni/bean ");    //In practice, you should ensure that your class, method, field exists.

Reduce this type of inference.

if(Bean_clz==null) {LOGE ("Can ' t find class");returnNULL; }//Gets the constructor function. The return value of the constructor is void, so here the method signature is finally vJmethodid Bean_init=env->getmethodid (BEAN_CLZ,"<init>","(ljava/lang/string;i) V");if(Bean_init==null) {LOGE ("can ' t find init function");returnNULL; }///Then call the constructor to get the beanJ Object Bean=env-NewObject(bean_clz,bean_init,msg,what) ; returnBean;}

Note: If you are prompted not to find null,include<stddef.h>

Parsing Java objects in C + +
//java方法Native声明publicnativegetString(Bean bean);
implementation of the method in//c++Jniexport jstring jnicall java_com_example_wastrel_hellojni_hellojni_getstring (JNIENV*env, Jobject obj,jobject Bean) {Jclass bean_clz=Env->findclass ("Com/example/wastrel/hellojni/bean");//This section is to get the corresponding value by the Get function//Jmethodid Bean_getmsg=env->getmethodid (BEAN_CLZ, "getmsg", "() ljava/lang/string;");//Jmethodid Bean_getwhat=env->getmethodid (BEAN_CLZ, "Getwhat", "() I");//Jstring jmsg= (jstring) Env->callobjectmethod (bean,bean_getmsg);//Jint What=env->callintmethod (bean,bean_getwhat);//This part takes the value directly from the member variable of the class. You may notice that the variables defined in Java are private-decorated. But there is no effect under the call of reflection. Jfieldid bean_fmsg=Env->getfieldid (BEAN_CLZ,"MSG","ljava/lang/string;"); Jfieldid bean_fwhat=Env->getfieldid (BEAN_CLZ,"What","I"); Jstring jmsg= (jstring)Env->getobjectfield (BEAN,BEAN_FMSG); Jint what=Env->getintfield (Bean,bean_fwhat);//Set a string back to the value you getconst char * msg=Env->getstringutfchars (Jmsg,null); Char*str=new char[1024x768]; sprintf (str,"msg:%s; what:%d (from C + +) ", msg,what); Jstring rs=Env->newstringutf (str);Delete[]str;Env->releasestringutfchars (JMSG,MSG);returnRS;}

Note: The sprintf function is included in the stdio.h header file.

Changing Java object property values in C + +
//java方法Native声明publicnativevoidModifyBean(Bean bean);
//c++ ImplementationJniexportvoidJnicall Java_com_example_wastrel_hellojni_hellojni_modifybean (jnienv*env, Jobject obj,jobject Bean) {Jclass Bean_clz=Env -Findclass ("Com/example/wastrel/hellojni/bean"); Jfieldid bean_fmsg=Env -Getfieldid (BEAN_CLZ,"MSG","ljava/lang/string;"); Jfieldid Bean_fwhat=Env -Getfieldid (BEAN_CLZ,"What","I"); Jstring msg=Env -Newstringutf ("Modify in C + +");//Set properties againEnv -Setobjectfield (BEAN,BEAN_FMSG,MSG); Env -Setintfield (Bean,bean_fwhat, -);return;}
Result diagram
//java中调用代码        HelloJNI helloJNI=new HelloJNI();        Bean bean=helloJNI.newBean("This is from C++ bean",10);        tv.setText(bean.toString());        bean=new Bean("This is from Java bean",15);        tv.append("\n"+helloJNI.getString(bean));        helloJNI.ModifyBean(bean);        tv.append("\n"+bean.toString());

Performance comparison of new object in new object and C + + in Java

The following we pass a test function to compare the performance of two ways, here can no doubt tell you that Java must be faster than C + +. The point of this comparison, then, is whether creating Java objects using C + + creates unacceptable lag.
The test machine used here is the Huawei Mate7, the detailed hardware configuration can be self-Baidu.
Test functions such as the following:

     voidTest (intCount) {LongStarttime=system.currenttimemillis (); for(intI=0; i<count;i++) {NewBean ("123", i); }LongEndtime=system.currenttimemillis (); LOG.E ("Java","Java new"+count+"s Waste"+ (Endtime-starttime) +"MS"); Hellojni hellojni=NewHellojni (); Starttime=system.currenttimemillis (); for(intI=0; i<count;i++) {Hellojni.newbean ("123", i);        } endtime=system.currenttimemillis (); LOG.E ("C + +","C + + new"+count+"s Waste"+ (Endtime-starttime) +"MS"); }

Test results:

java :  Java new 5000s waste 3ms  c++ : c++ new 5000s Waste 38ms  java : java new 10000s Waste 6ms  c++ : c++ new 10000s waste 79ms  Span class= "http" >java : java new 50000s waste 56ms  c++ : c++ new 50000s waste 338ms  java : java new 100000s waste 60ms  c++ : c++ new 100000s waste 687ms    

The result shows that the new object in C + + is 10 times times slower than Java. But in terms of time. Assume that you are simply new to a Java object in C + +. The time gap of several microseconds is completely negligible.

Maybe someone will say. C + + is so much slower because it is findclass,getmethodid every time. These two values are not changed during program execution. It does sound like a reason. Below we will change the code in C + + to cache Jclass and Jmethodid.
The Newbean function after the change:

//cache with static variablesStatic J class bean_clz=NULL;Static Jmethodid Bean_init=null; Jniexport J Object jnicall java_com_example_wastrel_hellojni_hellojni_newbean (JNIEnv *env, J object obj, jstring str,jint what) {    //Find class first    if(Bean_clz==null) {J class_bean_clz=env-findclass("com/example/ Wastrel/hellojni/bean ");  bean_clz= (Jclass) env->newglobalref (_BEAN_CLZ); }//Gets the constructor function. The return value of the constructor is void, so here the method signature is finally v    if(Bean_init==null) {Bean_init=env->getmethodid (BEAN_CLZ,"<init>","(ljava/lang/string;i) V"); }///Then call the constructor to get the beanJ Object Bean=env-NewObject(bean_clz,bean_init,str,what);    returnBean;}

You may find that the cache method ID and cache Jclass do not seem to be the same. That's because Jclass is actually a Java.lang.Class object, and the method ID is a struct defined in JNI. Assuming that the env—>NewGlobalRef() function is not declared here as a global reference, it is possible to make an error when executing: It JNI ERROR (app bug): accessed stale local reference 0x5900021 indicates that the object has been reclaimed in the JVM. The reference has expired. And Newglobalref's role is to tell the JVM. This reference has been held in C + + and should not be recycled. This, of course, raises another question. You need to call the JVM when you don't need the reference env->DelGlobalRef() . Of course you can also not call. Then the Java object will be recycled when your program is closed.

Test results:

java :  Java new 5000s waste 3ms  c++ : c++ new 5000s Waste 18ms  java : java new 10000s Waste 5ms  c++ : c++ new 10000s waste 24ms  Span class= "http" >java : java new 50000s waste 44ms  c++ : c++ new 50000s waste 121ms  java : java new 100000s waste 65ms  c++ : c++ new 100000s waste 259ms    

This time, the results show that the cache method ID and Jclass can be shortened by half the time. But still less fast than Java. This is also very well understood. C + + creating Java objects is finally created through Java, and repeating the creation by reflection is not as fast as the creation itself.

Summarize
    • In JNI, it is important to access the Java object method signature, class name, and variable name, so it is not easy to change the definition in Java once it is determined. A JNI error is raised because this causes JNI to find a related method or class, and so on.

    • Although JNI provides a variety of ways to complete the reflection operation of Java, use it as appropriate, as this makes the Java code overly dependent on the C + + code.
    • When you need to return the struct data in C + +, consider converting the struct to the corresponding Java object return.

Android Studio NDK Novice Tutorials (5)--java Object Transfer and change

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.