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
Developer
simon_hain
Posts: 16,113
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany
Accepted Solution

Download pictures on a separate thread?

I am using http://supportforums.blackberry.com/t5/Cascades-Development/Download-Images-Dynamically/m-p/1927137#...

successfully, but it seems that everything is done on the event thread, as the UI is not created before all of the images (12 atm, but can be more) are downloaded.

 

How would i move the download into another thread with Qt? Is there an executor queue that would be appropriate to use?

And do I have to get back to the event thread later on, like invokeLater in bbjava?

----------------------------------------------------------
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
Please use plain text.
Developer
simon_hain
Posts: 16,113
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: Download pictures on a separate thread?

Just answering my own question:

There is a simple mechanism, it is QtConcurrent
http://doc.qt.digia.com/stable/qtconcurrentrun.html
----------------------------------------------------------
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
Please use plain text.
Developer
Developer
mdd
Posts: 224
Registered: ‎01-17-2012
My Device: PB
My Carrier: ATT

Re: Download pictures on a separate thread?

@simon_hain

 

I'm attempting similar: reading a file/image in QNetworkReply's readyRead signal handler:

 

I've tried using QtConcurrent::run but UI response is sluggish at best, and also getting strange results (on simulator).

 

here is code that invoked in readyRead:

const QString TEXT_XML				= "text/xml";
const QByteArray contentDisposition	= "Content-Disposition";

ServerRequest::ServerRequest()
{
	m_bytes = 0;

	m_sink = NULL;
	m_reply = NULL;
	m_fileReader = NULL;

	m_state = 0;

	m_complete =
			m_finished = false;

	m_start.start();
}

ServerRequest::~ServerRequest()
{
	if ( m_pi.count() > 0 )
	{
		qDebug() << "stats:" << m_pi.toString();
	}
	qDebug() << "bytes:" << m_bytes << "elapsed:" << elapsed();
}

QFile* ServerRequest::dispose()
{
	if ( m_state == 0 )
	{
		if ( m_reply->hasRawHeader( contentDisposition ) )
		{
			QString name;

			if ( m_data.type() == QVariant::String )
			{
				name = m_data.toString();
			}
			else
			{
				QString hdr( m_reply->rawHeader( contentDisposition ) );
				QRegExp re( "filename=\"([^\"]+)\"" );

				if ( re.indexIn( hdr ) < 0 )
				{
					qDebug() << "failed to parse:" << hdr;
				}
				else
				{
					name = re.cap(1);
				}
			}

			if ( QDir::isAbsolutePath( name ) )
			{
				m_sink = new QFile( name );

				if ( m_sink->open( QFile::ReadWrite ) )
				{
					m_reader.insert( "filename", m_sink->fileName() );

					// Setup the reader thread

					m_fileReader = new FileReader( m_reply, m_sink );

					// Invoke our onFinished slot after the reading has finished.

					connect( &m_watcher, SIGNAL(finished()), this, SLOT(onFinished()) );
				}
			}
			m_state++;
		}
		else if ( m_reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith( TEXT_XML ) )
		{
			m_bytes += m_reply->bytesAvailable();

			m_reader.addData( m_reply->readAll() );
		}
	}
	if ( m_fileReader )
	{
		if ( m_state == 1 )
		{
			qint64 bytesToRead = m_reply->bytesAvailable();

			if ( bytesToRead < 0x80000 )
			{
				m_bytes += m_fileReader->start( bytesToRead );
			}
			else
			{
				m_state++;

				m_pi.setValue(bytesToRead);

				QFuture<qint64> future = QtConcurrent::run( m_fileReader, &FileReader::start, bytesToRead );

				m_watcher.setFuture( future );
			}
		}
	}
	return m_sink;
}

void ServerRequest::onFinished()
{
	m_bytes += m_watcher.future().result();
	m_state--;

	if ( m_complete )
	{
		complete();
	}
}

void ServerRequest::complete()
{
	if ( m_state > 1 )
	{
		qDebug() << "complete:" << m_state;

		m_complete = true;
	}
	else
	{
		if ( m_state == 1 )
		{
//			m_bytes += m_fileReader->start( m_reply->bytesAvailable() );

			m_sink->flush();
			m_sink->close();

			qDebug() << "saved:" << m_sink->fileName() << "bytes:" << m_bytes << "/" << m_sink->size();
		}

		emit finished( m_reader.xml() );
		deleteLater();
	}
}

 and here is the actual FileReader:

qint64 FileReader::start( qint64 bytesToRead )
{
	qint64 nRead = 0;

	while ( nRead < bytesToRead )
	{
		qint64 nBytes = bytesToRead - nRead;

		if ( nBytes > 0x800000 )
		{
			nBytes = 0x800000;
		}
		m_dst->write( m_src->read( nBytes ) );

		nRead += nBytes;
	}
	m_dst->flush();

	return nRead;
}

 I'm obviously missing some aspect of concurrent threading:


Questions:

   1. is onFinished in the UI thread or concurrent thread?  If it attempts to check bytesAvailable(), app crashes - call to pure virtual.

   2. even if "complete" reports saved m_bytes < Content-Length, the file is complete ??? (complete is also called from the http (GET) finished handler...)

 

Any suggestions welcome.

 

Regards,

Please use plain text.
Developer
simon_hain
Posts: 16,113
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: Download pictures on a separate thread?

please open your own thread. most people don't check on threads marked as solved. i'll check in there.
----------------------------------------------------------
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
Please use plain text.