Unsolved SD card removed notification
-
Hi,
I tried to implement a notification of SD card removal in my application on Android. There is a sample app and guide to do it. The sample works for me, but I stops working if I try to implement it in my application.
I tried to change the sample app to meet my needs and at one point it stopped working too. Basically the Java part works OK and even the callback to C++ on Android UI thread works. Originally it is implemented like this:
// native.cpp #include <jni.h> #include <QMetaObject> #include "mainwindow.h" /static void onReceiveNativeMounted(JNIEnv * /*env*/, jobject /*obj*/) { QMetaObject::invokeMethod(&MainWindow::instance(), "onReceiveMounted" , Qt::QueuedConnection); }
Then there is the mainwindow class:
// mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: static MainWindow &instance(QWidget *parent = 0); public slots: void onReceiveMounted(); void onReceiveUnmounted(); private: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; };
This construction works. Now all I did was to create my own class called AndroidLib and call it from the native.cpp. The modified part looks like this:
#include "androidlib.h" static void onReceiveNativeMounted(JNIEnv * /*env*/, jobject /*obj*/) { QMetaObject::invokeMethod(&AndroidLib::instance(), "onReceiveMounted" , Qt::QueuedConnection); }
The AndroidLib class looks almost identical to the former MainWindows class:
#ifndef ANDROIDLIB_H #define ANDROIDLIB_H #include <QObject> #include <QDebug> class AndroidLib : public QObject { Q_OBJECT public: explicit AndroidLib(QObject *parent = nullptr); static AndroidLib &instance(QObject *parent = 0); /*private: explicit AndroidLib(QObject *parent = nullptr);*/ public slots: void onReceiveMounted(); void onReceiveUnmounted(); signals: void sdMount(const bool mounted); }; #endif // ANDROIDLIB_H
The function in native.cpp is called. Even the function AndroidLib::instance() is called. But the function onReceiveMounted() in AndroidLib is not called.
Is there something wrong in the command
/QMetaObject::invokeMethod(&AndroidLib::instance(), "onReceiveMounted", Qt::QueuedConnection);
which causes that the function is not executed?
Thanks a lot for any advice regarding this issue.
-
@vlada
How isAndroidLib::instance()
exactly implemented?
The fact that you need to use a reference (&AndroidLib::instance()
) of the returned object seems a bit odd.
If you return an object allocated on the stack the function call will never happen, since it is destroyed before. -
The implementation can be found in the guide I mentioned in the beginning. It looks like this:
MainWindow &MainWindow::instance(QWidget *parent) { static MainWindow mainWindow(parent); return mainWindow; }
There is also explained, why it is a little bit more difficult then one would expect.
The problem is that the function in native.cpp is executed in Android UI thread and I need to call the function in AndroidLib so that it is called in Qt main loop.
After many trial and errors I finally made it to work although I'm not sure why. I found out that if I called the function in AndroidLib directly from main.cpp. Then it was executed. So I implemented a signal and connected it to the class when I needed the information. But that didn'T work.
Now I've used this in my code:
QObject::connect(&AndroidLib::instance(), SIGNAL(sdMount(bool)), qmltocpp, SLOT(sdMount(bool)));
And it works!!!! The function in AndroidLib is called, the signal is emitted and received in my qmltocpp class. Because C++ doesn't have a garbage collector, I hope the AndroidLib instance will not be destroyed. And I can always get the reference to it by calling the static instance() function. The constructor is now a private function as in the example. Maybe that was the trick, I'm really confused.
Now I need to move it to a service. That will be the next task. So the problem is solved but I still have no idea why it didn't work earlier and now it works.