Android Studio NDK Getting Started Tutorial (5)--java Object Transfer and modification

Source: Internet
Author: User
Tags 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, modifying Java objects, and performance comparisons.

Complete data conversion with JNIENV

Java objects exist in the JVM virtual machine, and C + + is run out of the JVM, and if you access and use objects in Java in C + +, you will use the JNIEnv bridge. In fact, it is easy to see from the following code that this kind of access is very similar to the reflection in Java.

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 kind of judgment.     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 part obtains the corresponding value through 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 section takes the values directly from the member variables of the class, and you may notice that the variables defined in Java are private, but are not useful under reflection calls. 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

Modifying 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 + +");//Reset PropertiesEnv -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

Below we have a test function to compare the performance in two ways, there is no doubt to tell you that Java must be faster than C + +. The implication of this contrast is that the use of C + + to create Java objects will not cause unacceptable lag.
The test machine used here is the Huawei Mate7, the specific hardware configuration can be Baidu itself.
The test function is as follows:

     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 about 10 times times slower than Java. But in terms of time, if you are just new Java object in C + +, a few microseconds of the time gap can be completely negligible.

Maybe some people will say that C + + is so much slower because it is findclass,getmethodid every time, and the two values will not change while the program is running. It sounds like there's a reason for this, and we'll make the code in C + + slightly modify the cache Jclass and Jmethodid.
The modified Newbean function:

//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. If you do not use env—>NewGlobalRef() a function to declare that it is a global reference, you may be able to make an error at run time: JNI ERROR (app bug): accessed stale local reference 0x5900021 It indicates that the object has been reclaimed in the JVM and the reference has been invalidated. And Newglobalref's role is to tell Jvm,c++ that the reference has been held, please do not recycle. Obviously this 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 if the cache method ID and Jclass can be shortened by half the time. But still less fast than Java. It's also good to understand that C + + creates Java objects that are ultimately created by Java, and that it is not as fast to create it by reflecting it over and over again.

Summarize
    • In JNI it is important to have access to the Java object method signature, class name, and variable name, so it is not easy to unilaterally modify 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, because it 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 Getting Started Tutorial (5)--java Object Transfer and modification

Related Article

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.