0

I am fairly new to Qt, and I am trying to do some Android Development. I am working with Qt and using the QAndroidJNIEnvironment. In the code, I am implementing my native method using QMetaObject::invokeMethod to invoke a slot in the QMainWindow header. The problem is that the native method in the java file has a parameter that is a java integer array(equivalent type I believe in QAndroindJniObject is jintArray). I can't find the corresponding c++/Qt type to place in the Q_ARG(type, value ) macro to resolve the argument. Please help me understand what I am doing wrong, as i thought the equivalent type to jintArray was int [], but I receive error when I use that. Thanks in advance for the help.

onReceiveNativeMounted (JNIEnv * env, jobject obj,jint array_index,jintArray version)
{

QMetaObject::invokeMethod(&MainWindow::instance(), "onReceiveMounted"
                          , Qt::QueuedConnection, Q_ARG(int, array_index),Q_ARG(int[], version));

 return array_index;
}

the error i receive is below:

error: no matching function for call to 
'QArgument<int []>::QArgument(const char [6], _jarray*&)'
 #define Q_ARG(type, data) QArgument<type >(#type, data)
                                                       ^

As requested, the java function signature is below:

public static native int onReceiveNativeMounted(int array_index, int[] version);
4
  • We can't answer that without seeing the signature for onReceiveMounted. The type you put in Q_ARG is the type of the argument from onReceiveMounted's signature. How you convert between the two types is up to you. Most likely you'll have to copy the array to a QVector or whatever native type is expected. Commented Sep 18, 2015 at 17:51
  • The signature is as follows: native int onReceiveNativeMounted(int array_index, int [] version); Commented Sep 18, 2015 at 18:00
  • 1
    A jintArray is not something you can convert into a C++ int array with something like a simple cast. I doubt that the QArgument class can do the required conversion for you. Commented Sep 18, 2015 at 18:39
  • That makes sense. Thanks for all your input. I really do appreciate you all taking the time to help me. Commented Sep 18, 2015 at 20:08

1 Answer 1

1

You need to access the java arrays according to the JNI API. The easiest thing to do is to convert the data to a QVector. You need to copy the Java array since its lifetime is not under your control (unless you wish it to be, but that makes life much harder than it needs to be).

QVector toQVector(JNIEnv * env, jintArray arr) {
  auto len = (*env)->GetArrayLength(env, arr);
  QVector result(len);
  auto data = (*env)->GetIntArrayElements(env, arr, 0);
  for (int i = 0; i < len; ++i)
    result[i] = data[i];
  (*env)->ReleaseIntArrayElements(env, arr, data, 0);
  return result;
}

It is a bit more performant to perform the call directly from a functor, rather than through invokeMethod. The functor can capture the vector:

int onReceiveNativeMounted (JNIEnv * env, jobject obj, jint array_index, jintArray version)
{
  auto window = &MainWindow::instance();
  auto vector = toQVector(env, version);
  QObject sig;
  sig.connect(&sig, &QObject::destroyed, window, [=]{
    window->onReceiveMounted(array_index, vector.data());
  }, Qt::QueuedConnection);
  return array_index;
}
Sign up to request clarification or add additional context in comments.

2 Comments

This worked nicely. I will have to read up on the performance enhancements of the connect method vs. the invoke method. Thanks again.
@DW_stack invokeMethod has to perform a lookup every time you do it. The new connect syntax doesn't have to, moreover there is no need to do any argument marshaling since you invoke a parameterless functor. All the marshaling is done as lambda environment capture, by the compiler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.