Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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.


  • Moderators

    @vlada
    How is AndroidLib::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.


Log in to reply