Results 1 to 3 of 3

Thread: Converting QAndroidJniObject to jobjectArray: most elements are NULL!

  1. #1
    Join Date
    May 2009
    Location
    Canada
    Posts
    163
    Thanks
    7
    Thanked 20 Times in 20 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Windows Android

    Default Converting QAndroidJniObject to jobjectArray: most elements are NULL!

    Hello,

    I am trying to get a list of audio track info from an Android device. On the Java side, this is accomplished with a static getMusic() method, which returns List<AudioTrack>. getMusic() lives in my custom AndroidDeviceMediaCollection class. AudioTrack is essentially a struct of various fields, with a toString() method. I am able to instantiate each AudioTrack that I expect to find, print it out in Java using toString(), and then add it to the list. But I am running into problems on the C++ side. In particular, it seems that I am not able to convert the returned List<AudioTrack>, which is held in a QAndroidJniObject, to a jobjectArray without destroying most of its contents! Here is the relevant C++ code:

    Qt Code:
    1. GenericModel<Album>* AndroidDeviceMediaCollection::albumsModel() {
    2. QPlatformNativeInterface *interface = QApplication::platformNativeInterface();
    3. jobject activity = (jobject) interface->nativeResourceForIntegration("QtActivity");
    4. QAndroidJniObject music = QAndroidJniObject::callStaticObjectMethod("org.qtproject.mythings.AndroidDeviceMediaCollection", "getMusic", "(Landroid/content/Context;)Ljava/util/List;", activity);
    5. Q_ASSERT_X(music.isValid(), "albumsModel", "Null QAndroidJniObject!");
    6. jobjectArray musicArray = music.object<jobjectArray>();
    7. QAndroidJniEnvironment qjniEnv;
    8. const int n = qjniEnv->GetArrayLength(musicArray);
    9. qDebug() << "Got jobjectArray of length:" << n; // prints expected value
    10. for (int i = 0; i < n; ++i) {
    11. jobject jAudioTrack = qjniEnv->GetObjectArrayElement(musicArray, i);
    12. if (jAudioTrack) {
    13. // parse, add to albums...
    14. qjniEnv->DeleteLocalRef(jAudioTrack);
    15. }
    16. else
    17. qDebug() << "Got null jAudioTrack at index:" << i; // most elements are null!
    18. }
    19. return &m_albums;
    20. }
    To copy to clipboard, switch view to plain text mode 

    To be clear, I am successfully converting to a jobjectArray with exactly the right number of elements, but for most of those elements I see the null debug message.

    I was just wondering if someone could point out what I am doing wrong here, or if there is a different way to acquire and iterate over a list of instances of a custom type. Any insight appreciated. Thank you!

  2. #2
    Join Date
    May 2009
    Location
    Canada
    Posts
    163
    Thanks
    7
    Thanked 20 Times in 20 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Windows Android

    Default Re: Converting QAndroidJniObject to jobjectArray: most elements are NULL!

    Update: So I've smashed my head against this since posting, and have made some progress by returning AudioTrack[] instead of List<AudioTrack>. Hardly ideal, and if someone can shed some light on returning and manipulating a List I should be much obliged, but I must confess too that I'm just glad to feel like I am progressing!

    Java:

    Qt Code:
    1. public static AudioTrack[] getMusic(Context context) {
    2. List<AudioTrack> music = new ArrayList<AudioTrack>();
    3. // ...
    4. return music.toArray(new AudioTrack[0]);
    5. }
    To copy to clipboard, switch view to plain text mode 

    Qt:

    Qt Code:
    1. GenericModel<Album>* AndroidDeviceMediaCollection::albumsModel() {
    2. QPlatformNativeInterface *interface = QApplication::platformNativeInterface();
    3. jobject activity = (jobject)interface->nativeResourceForIntegration("QtActivity");
    4. QAndroidJniObject music = QAndroidJniObject::callStaticObjectMethod("org.qtproject.mythings.AndroidDeviceMediaCollection",
    5. "getMusic",
    6. "(Landroid/content/Context;)[Lorg/qtproject/mythings/AudioTrack;",
    7. activity);
    8. Q_ASSERT_X(music.isValid(), "albumsModel", "Null QAndroidJniObject!");
    9. jobjectArray objectArray = music.object<jobjectArray>();
    10. qDebug() << "Got jobject of type:" << getObjectClass(objectArray); // correct
    11. QAndroidJniEnvironment qjniEnv;
    12. const int n = qjniEnv->GetArrayLength(objectArray);
    13. qDebug() << "Got jobjectArray of length:" << n; // correct
    14. for (int i = 0; i < n; ++i) {
    15. qDebug() << "Iteration:" << i;
    16. jobject element = qjniEnv->GetObjectArrayElement(objectArray, i);
    17. qDebug() << "Got jobject of type:" << getObjectClass(element); // correct
    18. // ...
    19. qjniEnv->DeleteLocalRef(element);
    20. }
    21. return &m_albums;
    22. }
    23.  
    24. /* Much of this code comes from http://stackoverflow.com/questions/12719766/can-i-know-the-name-of-the-class-that-calls-a-jni-c-method */
    25. const char * AndroidDeviceMediaCollection::getObjectClass(jobject object) {
    26. Q_ASSERT_X(object, "getObjectClass", "Null jobject!");
    27. QAndroidJniEnvironment qjniEnv;
    28. jclass cls = qjniEnv->GetObjectClass(object);
    29.  
    30. // First get the class object
    31. jmethodID mid = qjniEnv->GetMethodID(cls, "getClass", "()Ljava/lang/Class;");
    32. jobject clsObj = qjniEnv->CallObjectMethod(object, mid);
    33.  
    34. // Now get the class object's class descriptor
    35. cls = qjniEnv->GetObjectClass(clsObj);
    36.  
    37. // Find the getName() method on the class object
    38. mid = qjniEnv->GetMethodID(cls, "getName", "()Ljava/lang/String;");
    39.  
    40. // Call the getName() to get a jstring object back
    41. jstring strObj = (jstring)qjniEnv->CallObjectMethod(clsObj, mid);
    42.  
    43. // Now get the c string from the java jstring object
    44. const char *str = qjniEnv->GetStringUTFChars(strObj, NULL);
    45.  
    46. // Java uses '.' class name delimiter, whereas JNI uses '/' -- convert accordingly!
    47. const QByteArray byteArray = QString(str).split(".").join("/").toLatin1();
    48. const char *clazz = byteArray.data();
    49.  
    50. // Release memory
    51. qjniEnv->ReleaseStringUTFChars(strObj, str);
    52.  
    53. return clazz;
    54. }
    To copy to clipboard, switch view to plain text mode 

    That is to say, I can iterate through the returned array which is of the expected size, and each element is not null and is of type AudioTrack.
    Last edited by Urthas; 27th May 2014 at 02:32.

  3. #3
    Join Date
    May 2009
    Location
    Canada
    Posts
    163
    Thanks
    7
    Thanked 20 Times in 20 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Windows Android

    Default Re: Converting QAndroidJniObject to jobjectArray: most elements are NULL!

    Final (?) update: for completion and the edification of others, here is all of the relevant Qt code with which I am accessing the information in an array of objects of custom type AudioTrack. Note that error detection/handling leaves much to be desired.

    Qt Code:
    1. GenericModel<Album> * AndroidDeviceMediaCollection::albumsModel() {
    2. if (m_albums.count() == 0) {
    3. QPlatformNativeInterface * const interface = QApplication::platformNativeInterface();
    4. const jobject activity = (jobject) interface->nativeResourceForIntegration("QtActivity");
    5. const QAndroidJniObject music = QAndroidJniObject::callStaticObjectMethod("org.qtproject.mythings.AndroidDeviceMediaCollection",
    6. "getMusic",
    7. "(Landroid/content/Context;)[Lorg/qtproject/mythings/AudioTrack;",
    8. activity);
    9. Q_ASSERT_X(music.isValid(), "albumsModel", "Null QAndroidJniObject!");
    10. const jobjectArray musicArray = music.object<jobjectArray>();
    11. QAndroidJniEnvironment qjniEnv;
    12. const int n = qjniEnv->GetArrayLength(musicArray);
    13. jclass clazz = 0;
    14. for (int i = 0; i < n; ++i) {
    15. const jobject jAudioTrack = qjniEnv->GetObjectArrayElement(musicArray, i);
    16. Q_ASSERT_X(jAudioTrack, "albumsModel", "Null jobject!");
    17. if (clazz == 0) {
    18. const jclass tmp = qjniEnv->GetObjectClass(jAudioTrack);
    19. Q_ASSERT_X(tmp, "albumsModel", "Null jclass!");
    20. clazz = (jclass) qjniEnv->NewGlobalRef(tmp);
    21. Q_ASSERT_X(clazz, "albumsModel", "Null jclass!");
    22. }
    23. else
    24. Q_ASSERT_X(qjniEnv->IsInstanceOf(jAudioTrack, clazz), "albumsModel", "jobject is not of the expected type!");
    25. /* Parse fields... */
    26. const jfieldID albumIDFieldID = qjniEnv->GetFieldID(clazz, "albumID", "I");
    27. const jint albumID = qjniEnv->GetIntField(jAudioTrack, albumIDFieldID);
    28. // ...
    29. qjniEnv->DeleteLocalRef(jAudioTrack);
    30. }
    31. qjniEnv->DeleteGlobalRef(clazz);
    32. if (qjniEnv->ExceptionCheck()) {
    33. qjniEnv->ExceptionDescribe();
    34. Q_ASSERT(false);
    35. }
    36. }
    37. return &m_albums;
    38. }
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. How to use QAndroidJniObject for intent.setData?
    By Clever&Smart in forum Qt for Embedded and Mobile
    Replies: 2
    Last Post: 17th December 2015, 17:36
  2. Can’t create java class by QAndroidJniObject
    By stereoMatching in forum Qt for Embedded and Mobile
    Replies: 1
    Last Post: 10th February 2014, 18:40
  3. Set NULL values
    By LaTj in forum Newbie
    Replies: 1
    Last Post: 7th October 2013, 22:55
  4. Null for QDateEdit
    By wirasto in forum Qt Programming
    Replies: 1
    Last Post: 16th November 2009, 22:54
  5. QPixmap seems to be null but it isn't
    By satoshi in forum Qt Programming
    Replies: 7
    Last Post: 8th May 2009, 10:23

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.