Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Highlighted
Contributor
Posts: 15
Registered: ‎07-18-2013
My Device: 9800
My Carrier: Airtel
Accepted Solution

Static class instance.

I am working on my database helper class. My need is to have a single instance of this class throughout the application. In BB cascades development we have to create an object of the class to access its functions in a different class and in qml we must have the class as an attached object so that we can call the method within it by the id declared. But i dont want my database class instance to be created each time i want to call a database helper class function but only the first time when the user logs in to the application. I want this instance to be available throughout the application. Please do advice if you have successfully solved this issue. Any code bit is also welcome. Thanks in advance.

Developer
Posts: 1,008
Registered: ‎12-12-2010
My Device: Passport (Red Limited Edition)
My Carrier: Mobile Vikings

Re: Static class instance.

Since I am a bit lazy today I will give you a peak at my DbHelper class that I use in all my projects.

 

/*
 * DbHelper.cpp
 *
 *  Created on: Jan 8, 2013
 *      Author: Bram Vandewalle
 */

#include "DbHelper.hpp"

bool DbHelper::instanceFlag = false;
DbHelper* DbHelper::singleton = NULL;

DbHelper* DbHelper::getInstance()
{
	if(!instanceFlag)
	{
		singleton = new DbHelper();
		instanceFlag = true;
	}
	return singleton;
}

DbHelper::DbHelper()
{
	qDebug() << "Constructing DbHelper...";
	mDbNameWithPath = "";
	loadDataBase("pages.db");
}

DbHelper::~DbHelper()
{
    if (mDb.isOpen()) {
        QSqlDatabase::removeDatabase(mDbNameWithPath);
        mDb.removeDatabase("QSQLITE");
    }
    instanceFlag = false;
}

bool DbHelper::loadDataBase(const QString databaseName)
{
    if (copyDbToDataFolder(databaseName))
    {
        mDbNameWithPath = "data/" + databaseName;
        QFile copiedDbFile(mDbNameWithPath);
        if(copiedDbFile.exists())
        {
        	qDebug() << "Copied db files exists!";
        }
        else
        {
        	qDebug() << "Copied db files does not exist!";
        }
        // Set up a SqlDataAccess object.
        SqlDataAccess sqlDataAccess(mDbNameWithPath);
        if (sqlDataAccess.hasError())
        {
            DataAccessError err = sqlDataAccess.error();
            qWarning() << "SQL error: type=" << err.errorType() << ": " << err.errorMessage();
            return false;
        }
        // Open the database to enable update/insert/delete functionality (via SQL queries) using
        // a non-default connection, so we don't conflict with the database connection already setup by SqlDataAccess.
        mDb = QSqlDatabase::addDatabase("QSQLITE", "database_helper_connection");
        mDb.setDatabaseName(mDbNameWithPath);
        if (!mDb.isValid())
        {
            qWarning() << "Could not set data base name probably due to invalid driver.";
            return false;
        }
        bool success = mDb.open();
        if (!success)
        {
            qWarning() << "Could not open database we are in trouble";
            return false;
        }
        return true;
    }
    return false;
}

bool DbHelper::copyDbToDataFolder(const QString databaseName)
{
	this->databaseName = databaseName;

    // Since we need read and write access to the database, it has
    // to be moved to a folder where we have access to it. First
    // we check if the file already exists (previously copied).
    QString dataFolder = QDir::homePath();
    QString newFileName = dataFolder + "/" + databaseName;
    QFile newFile(newFileName);

    if (!newFile.exists())
    {
        // If the file is not already in the data folder, we copy it from the
        // assets folder (read only) to the data folder (read and write).
        // You should note that on a debug build, you will be able to write to a database
        // in the assets folder. However, for a signed application, it is not possible to
        // write to the database in the assets folder.
        QString appFolder(QDir::homePath());
        appFolder.chop(4);
        QString originalFileName = appFolder + "app/native/assets/data/" + databaseName;
        QFile originalFile(originalFileName);

        if (originalFile.exists()) {
            return originalFile.copy(newFileName);
        } else {
            qWarning() << "Failed to copy file data base file does not exists.";
            return false;
        }

    }
    return true;
}

void DbHelper::removeDatabase()
{
	QString dataFolder = QDir::homePath();
	QFile database(dataFolder + "/" + databaseName);

	if(database.exists()) {
		database.remove();
	}
}

QList<QVariant> DbHelper::fetchStuff()
{
	QSqlQuery sqlQuery(mDb);
	QList<QVariant> list;
	QString query = QString("SELECT * FROM table;");
	if(sqlQuery.exec(query))
	{
		while(sqlQuery.next())
		{
			//Do stuff here
			list.append(new object);
		}
	}
	return list;
}

 

-------------------------------------------
BlackBerry Certified Builder for Native Application Development -- Proud member of the Belgian BlackBerry Developer group
Samples: Park in Ghent
Feeling generous? Nominate me for BB Elite member!
Developer
Posts: 17,025
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: Static class instance.

you can create the instance even easier:

MyClass* MyClass::instance() {
	static MyClass instance;
	return &instance;
}

 

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Contributor
Posts: 15
Registered: ‎07-18-2013
My Device: 9800
My Carrier: Airtel

Re: Static class instance.

[ Edited ]

I need to know two more things on this post

1. I am not able to declare the constructor under the private section in the header file. So what could be the possible reason.

2. How do we invoke this static instance as an attached object if its operations are required in the qml page as its constructor cannot be called?

Developer
Posts: 17,025
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: Static class instance.

1. no clue. try to create a new class, does it work there?
2. i use setProperty with the instance method
----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: Static class instance.

[ Edited ]

1. Constructor should be public, otherwise you won't be able to instantiate the class on this line:

static MyClass instance;

 

2. When using attachedObjects, new instances will be created each time the object is declared. If you have a singleton, you can export it to QML like this:

qml->setContextProperty("_myInstance", MyClass::instance());

And reference it anywhere in QML as _myInstance:

_myInstance.myMethod()

etc

 

 

 


Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 17,025
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: Static class instance.


Zmey wrote:

1. Constructor should be public


Why is that? The constructor of a singleton is usually private, only the instance() method is public.

----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Developer
Posts: 1,524
Registered: ‎12-18-2012
My Device: Z30, Z10 LE, DevAlpha C, PlayBook

Re: Static class instance.

I'm sorry, you are right. It should work.

Andrey Fidrya, @zmeyc on twitter
Developer
Posts: 1,008
Registered: ‎12-12-2010
My Device: Passport (Red Limited Edition)
My Carrier: Mobile Vikings

Re: Static class instance.

Since the original author was requesting for the header file, here it is!

 

/*
 * DbHelper.hpp
 *
 *  Created on: Jan 8, 2013
 *      Author: Bram Vandewalle
 */

#ifndef DBHELPER_HPP_
#define DBHELPER_HPP_

#include <QObject>
#include <QtSql/QtSql>
#include <bb/data/SqlDataAccess>

using namespace bb::data;

class DbHelper : public QObject
{
	Q_OBJECT;
public:
	/**
	 * Method to acquire the singleton instance
	 */
	static DbHelper* getInstance();

	DbHelper();
	/**
	 * Destructor
	 */
    ~DbHelper();
    /**
     * Removes the database from the filesystem
     */
    void removeDatabase();

    /**
     * Fetches all pages from the database (non-deleted only)
     */
    QList<QVariant> fetchPages();

private:
	static bool instanceFlag;
	static DbHelper* singleton;

    /**
     * This function loads all the entries in a specific table using SqlDataAccess which
     * is designed to help setup a data structure for a GroupDataModel ( which can can be used
     * to populate a list in Cascades).
     *
     * @param table The name of the table.
     * @param databaseName The name of the database (in assets/sql).
     * @return A list set up to be added to a GroupDataModel.
     */
    bool loadDataBase(const QString databaseName);
    /**
     * In order to write to a file in a signed application, the file must
     * reside in the apps data folder(assets). This function copies the bundled
     * database file to that folder.
     *
     * @param databaseName The name of the database (in assets/sql).
     * @return True on success, false on failure
     */
    bool copyDbToDataFolder(const QString databaseName);

    // The database is opened in the loadDatabase function.
    QSqlDatabase mDb;

    // The name of the table loaded in the loadDatabase function
    QString mDbNameWithPath;

    // The name of the database
    QString databaseName;
};

#endif /* DBHELPER_HPP_ */

 

-------------------------------------------
BlackBerry Certified Builder for Native Application Development -- Proud member of the Belgian BlackBerry Developer group
Samples: Park in Ghent
Feeling generous? Nominate me for BB Elite member!
Contributor
Posts: 15
Registered: ‎07-18-2013
My Device: 9800
My Carrier: Airtel

Re: Static class instance.

setProperty method is working fine when we are pushing a qml page from a cpp file. But how do we set the singleton instance property to a qml page if its being pushed from another qml page.