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
Trusted Contributor
Brennan12325
Posts: 204
Registered: ‎05-15-2012
My Device: None
My Carrier: Telus

Loading an Image (from a URL) into a ListView

I'm curious as to the proper way to implement the updateItem function in a class extending CustomControl and ListItemListener, when loading a picture from an online resource. I'm constructing a FileDownloader and downloading the image every time updateItem is called (which is every time the item comes into view). This isn't a great solution (since you might download the image multiple times), but I think it should work. It doesn't work.

 

I get all kinds of "Context: Failed to find target node" with my current implementation, I'm not sure it's relatead to the crash, but I only get these errors when I have the ImageView code active, and it only crashes when that code is active.

 

Errors:

Context: Failed to find target node with id  1230 
Context: Failed to find target node with id  1230 
Context: Failed to find target node with id  1227 
Context: Failed to find target node with id  1229 
Context: Failed to find target node with id  1235 
Context: Failed to find target node with id  1235 
Context: Failed to find target node with id  1239 
Context: Failed to find target node with id  1239 
Context: Failed to find target node with id  1241 
Context: Failed to find target node with id  1240 
Context: Failed to find target node with id  1247 
Context: Failed to find target node with id  1247 
Context: Failed to find target node with id  1248 
Context: Failed to find target node with id  1248 
Context: Failed to find target node with id  1250 
Context: Failed to find target node with id  1250 
Context: Failed to find target node with id  1255 
Context: Failed to find target node with id  1255 
Context: Failed to find target node with id  1256 
Context: Failed to find target node with id  1256 
Context: Failed to find target node with id  1257 
Context: Failed to find target node with id  1257 
Got into replyFinished 
Response Length: 29315
Done in replyFinished 
"POST ID: 16716l" 
"POST ID: 166hg8" 
"POST ID: 1670bb" 

 

Some code:

 

Constructing CustomControl ImageView (I place a loading image in its place until the SLOT from FileDownloader executes and loads the image downloaded from a URL in its place):

    m_ThumbnailImage = ImageView::create("asset:///images/loading.png").preferredSize(120.0f, 120.0f);
    m_ThumbnailImage->setHorizontalAlignment(HorizontalAlignment::Center);
    m_ThumbnailImage->setVerticalAlignment(VerticalAlignment::Center);

 

updateItem function (ImageView portion of the code):

	if(thumbnailURL == "self")
	{
		thumbnail = Image(QUrl("asset:///images/rightSelfArrow.png"));
		m_ThumbnailImage->setImage(thumbnail);
	}
	else if(thumbnailURL == "")
	{
		thumbnail = Image(QUrl("asset:///images/rightArrowFull.png"));
		m_ThumbnailImage->setImage(thumbnail);
	}
	else if(url.isValid())
	{
		m_ThumbnailDownloader = new FileDownloader(thumbnailURL, this);
		connect(m_ThumbnailDownloader, SIGNAL(downloaded()), SLOT(loadImage()));
	}
	else
	{
//never hit Q_ASSERT(false); }

This problem is completely alleviated if I remove the above block of code from my updateItem function.

 

It's worth noting I occasionally remove many items from the ListView DataModel, and that appears to be related to this problem. I remove items simply using DataModel.removeAt(x). Perhaps I need to dealloc the image or something?

 

Here's the error I eventually get:

segfault.png

 

The seg fault tells me nothing, but maybe somebody else has seen a similar issue?

----------------------
Check out my app, Alien Flow for reddit

And of course, like my post if you found it helpful or informative!
Please use plain text.
Trusted Contributor
Brennan12325
Posts: 204
Registered: ‎05-15-2012
My Device: None
My Carrier: Telus

Re: Loading an Image (from a URL) into a ListView

Forgot that my FileDownloader class isn't a Qt class, here's the source for it:

 

.cpp

FileDownloader::FileDownloader(QUrl imageUrl, QObject *parent) :
	QObject(parent)
{
	connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)),
				SLOT(fileDownloaded(QNetworkReply*)));
	QNetworkRequest request(imageUrl);
	m_WebCtrl.get(request);
}
FileDownloader::~FileDownloader(){}
void FileDownloader::fileDownloaded(QNetworkReply* pReply)
{
	m_DownloadedData = pReply->readAll();
	//emit a signal
	emit downloaded();
}
QByteArray FileDownloader::downloadedData() const
{
	return m_DownloadedData;
}

 .h

class FileDownloader : public QObject
{
	Q_OBJECT
public:
	explicit FileDownloader(QUrl imageUrl, QObject *parent = 0);
	virtual ~FileDownloader();
	QByteArray downloadedData() const;
signals:
		void downloaded();
private slots:
	void fileDownloaded(QNetworkReply* pReply);
private:
	QNetworkAccessManager m_WebCtrl;
	QByteArray m_DownloadedData;
};

 

----------------------
Check out my app, Alien Flow for reddit

And of course, like my post if you found it helpful or informative!
Please use plain text.
Developer
dridk
Posts: 91
Registered: ‎09-25-2012
My Device: bb10 alpha
My Carrier: free

Re: Loading an Image (from a URL) into a ListView

What I did is to use the WebImageView provided here : http://supportforums.blackberry.com/t5/Cascades-Development/Will-ImageView-ImageTracker-support-web-...

 

 

Then, you just have to add WebImageView et setUrl. Image dowloading will be done automatically. 

 

 

a lover of Qt
Please use plain text.
Developer
dridk
Posts: 91
Registered: ‎09-25-2012
My Device: bb10 alpha
My Carrier: free

Re: Loading an Image (from a URL) into a ListView

[ Edited ]

anyway, How many FileDownloader do you construct ? It's seems you make a request on each construction and use many QNetworkAccessmanger ! 

So, 

 

FileDownloader fileA;

FileDownloader fileB;

 

Will use 2 QNetworkAcessManager. You should have only one instance .

 

So the good way is : 

 

QNetworkReply * reply = mNetManager->get(request);

connect(reply,SIGNAL(finished()),this,SLOT(loaded());

 

void Class::loaded()

{

QNetworkReply * reply  = qobject_cast<QNetworkReply*>(sender());

 

reply->readAll();

reply->deleteLater();

 

}

 

a lover of Qt
Please use plain text.
Trusted Contributor
Brennan12325
Posts: 204
Registered: ‎05-15-2012
My Device: None
My Carrier: Telus

Re: Loading an Image (from a URL) into a ListView

Thanks for the tip! I've more or less been working on it all day.

 

I'm honestly not particularly sure what the issue was with my old solution, I think VisualNode's may have been getting killed before receiving signals meant for them, causing the seg fault.

 

In any case, I managed to integrate the image downloader demonstrated here:

https://github.com/blackberry/Cascades-Samples/tree/master/tldr/assets

into my code.

 

This is still causing issues, though, and it appears to once again be the ListView's reuse of VisualNode elements that is causing the issue.  It is hard to manage keeping track of signals on the node's when a reused node may have a signal attached from an element it had displayed prior.

 

I guess this is just fair warning to anyone else who decides to extend CustomControl and ListItemListener in C++. Be VERY careful about connects you make to the VisualNode's, because they will persist when the VisualNode is reused and could potentially cause issues.

----------------------
Check out my app, Alien Flow for reddit

And of course, like my post if you found it helpful or informative!
Please use plain text.
Trusted Contributor
Brennan12325
Posts: 204
Registered: ‎05-15-2012
My Device: None
My Carrier: Telus

Re: Loading an Image (from a URL) into a ListView

Just a note on using one network manager. That is the proper way to do things, but you have to be very careful that you don't have multiple elements (especially in a list where you likely have multiple elements listening for responses!) all receive a finished signal, and load the same image into their list element.

 

The solution is to connect to the reply objects "finished()" signal, instead of the QNetworkAccessManager finished(QNetworkReply*) signal. To get the QNetworkReply* in your SLOT for finished() you need to execute this code on the first line:

QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());

 since it is not included as a parameter in the finished signal of the QNetworkReply object.

 

Here's an article with further explanation:

http://www.johanpaul.com/blog/2011/07/why-qnetworkaccessmanager-should-not-have-the-finishedqnetwork...

 

I think once I manage to modify the example I linked to in my previous post (that I just implemented), to handle network replies in such a manner, I will have solved my problem. I will keep the thread posted, anyways.

----------------------
Check out my app, Alien Flow for reddit

And of course, like my post if you found it helpful or informative!
Please use plain text.