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);
DW_stack
  • 1
  • 3
  • 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. – Kuba hasn't forgotten Monica Sep 18 '15 at 17:51
  • The signature is as follows: native int onReceiveNativeMounted(int array_index, int [] version); – DW_stack Sep 18 '15 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. – Michael Sep 18 '15 at 18:39
  • That makes sense. Thanks for all your input. I really do appreciate you all taking the time to help me. – DW_stack Sep 18 '15 at 20:08

1 Answers1

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;
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • 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 Sep 22 '15 at 14:40
  • @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. – Kuba hasn't forgotten Monica Sep 22 '15 at 15:03