Cocos2d-x3.2 TextureCache类异步加载功能讲解

本文TextureCache类异步加载功能的代码抽出,总共代码就200多行,感兴趣可以看看。

研究这个主要是因为项目中需要异步插入数据,但之前的方法在Android上总是崩溃所以想到TextureCache有异步加载的功能就将其抽出了。

原文地址:http://blog.csdn.net/qqmcy/article/details/39890837

首先,创建AsyncTaskTime类,主要模拟一个费时的方法

AsyncTaskTime.h

#include "cocos2d.h"

USING_NS_CC;

class AsyncTaskTime
{
public:

    //模拟一个费时操作
    bool initWithImageFileThreadSafe(const std::string &filename);

};

AsyncTaskTime.cpp

//
//  AsyncTaskTime.cpp
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#include "AsyncTaskTime.h"

bool AsyncTaskTime::initWithImageFileThreadSafe(const std::string &filename)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    return true;
}

创建异步加载功能类

AsyncTest.h

//
//  AsyncTest.h
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#ifndef __cpp4__AsyncTest__
#define __cpp4__AsyncTest__

#include "cocos2d.h"
#include "AsyncTaskTime.h"

using namespace std;

USING_NS_CC;
class AsyncTest : public Ref
{
public:
    CREATE_FUNC(AsyncTest);

    virtual bool init();

    AsyncTest();

    // 异步加载
    void addImageAsync(const string &path , const function<void(AsyncTaskTime *)> &callback);
private:

    void addImageAsyncCallback(float dt);
    //加载数据
    void loadImage();

public:
    struct AsyncStruct
    {
    public:
        AsyncStruct(const string &fn , function<void(AsyncTaskTime *)> f): filename(fn) , callback(f){};

        string filename;
        function<void(AsyncTaskTime *)> callback;
    };

protected:

    typedef struct
    {
        AsyncStruct *asyncStruct;
        AsyncTaskTime *image;
    }ImageInfo;

    thread *_loadingThread;
    queue<AsyncStruct *>        *_asyncStructQueue;
    deque<ImageInfo *>          *_ImageInfoQueue;

    mutex                       _asyncStructQueueMutex;
    mutex                       _imageInfoMutex;

    mutex                       _sleepMutex;
    condition_variable          _sleepCondition;

    bool                        _needQuit;
    int                         _asyncRefCount;
    unordered_map<std::string , AsyncTaskTime* > _textures;

};

#endif /* defined(__cpp4__AsyncTest__) */

AsyncTest.cpp

//
//  AsyncTest.cpp
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#include "AsyncTest.h"

AsyncTest::AsyncTest()
: _loadingThread(nullptr)
, _asyncStructQueue(nullptr)
, _ImageInfoQueue(nullptr)
, _needQuit(false)
, _asyncRefCount(0)
{

}

bool AsyncTest::init()
{
    return true;
}

void AsyncTest::addImageAsync(const string &path, const function<void (AsyncTaskTime *)> &callback)
{
    AsyncTaskTime *texture = nullptr;

    auto it = _textures.find(path);
    if (it != _textures.end()) {
        texture = it->second;
    }

    if (texture != nullptr) {
        callback(texture);
        return;
    }

    if (_asyncStructQueue == nullptr) {
        _asyncStructQueue = new queue<AsyncStruct *>();
        _ImageInfoQueue = new deque<ImageInfo *>();

        _loadingThread = new thread(&AsyncTest::loadImage , this);

        _needQuit = false;
    }

    if (0 == _asyncRefCount) {
        Director::getInstance()->getScheduler()->schedule(schedule_selector(AsyncTest::addImageAsyncCallback), this, 0, false);
    }

    ++_asyncRefCount;

    auto data = new AsyncStruct(path , callback);

    _asyncStructQueueMutex.lock();
    _asyncStructQueue->push(data);
    _asyncStructQueueMutex.unlock();

    _sleepCondition.notify_one(); //将等待 condition_variable 对象的其中一个线程解除阻塞。

}

void AsyncTest::loadImage()
{
    AsyncStruct *asyncStruct = nullptr;
    while (true) {
        queue<AsyncStruct *> *pQueue = _asyncStructQueue;
        _asyncStructQueueMutex.lock();
        if (pQueue->empty()) {

        }
        else{
            asyncStruct = pQueue->front();
            pQueue->pop();
            _asyncStructQueueMutex.unlock();
        }

        AsyncTaskTime *image = nullptr;
        bool generateImage = false;

        auto it = _textures.find(asyncStruct->filename);
        if (it == _textures.end()) {
            _imageInfoMutex.lock();
            ImageInfo *imageInfo;
            size_t pos = 0;
            size_t infoSize = _ImageInfoQueue->size();
            for (; pos < infoSize; pos++) {
                imageInfo = (*_ImageInfoQueue)[pos];
                if (imageInfo->asyncStruct->filename.compare(asyncStruct->filename) == 0)
                    break;

            }
            _imageInfoMutex.unlock();
            if (infoSize == 0 || pos == infoSize)
                generateImage = true;

        }

        if (generateImage) {
            const string &filename = asyncStruct->filename;
            image = new AsyncTaskTime();
            if (image && !image->initWithImageFileThreadSafe(filename)) {
                continue;
            }
        }

        auto imageInfo = new ImageInfo();
        imageInfo->asyncStruct = asyncStruct;
        imageInfo->image = image;

        _imageInfoMutex.lock();
        _ImageInfoQueue->push_back(imageInfo);
        _imageInfoMutex.unlock();

    }

    if (_asyncStructQueue != nullptr) {
        delete _asyncStructQueue;
        _asyncStructQueue = nullptr;
        delete _ImageInfoQueue;
        _ImageInfoQueue = nullptr;
    }

}

void AsyncTest::addImageAsyncCallback(float dt)
{
    deque<ImageInfo *> *imagesQueue = _ImageInfoQueue;
    _imageInfoMutex.lock();
    if (imagesQueue->empty()) {
        _imageInfoMutex.unlock();
    }
    else{
        auto imageInfo = imagesQueue->front();
        imagesQueue->pop_front();
        _imageInfoMutex.unlock();

        auto asyncStruct = imageInfo->asyncStruct;
        auto image = imageInfo->image;
        if (asyncStruct->callback) {
            asyncStruct->callback(image);
        }

        --_asyncRefCount;
        if (0 == _asyncRefCount) {
            Director::getInstance()->getScheduler()->unschedule(schedule_selector(AsyncTest::addImageAsyncCallback), this);
        }
    }
}

调用:

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "AsyncTest.h"
USING_NS_CC;

class HelloWorld : public cocos2d::Layer
{
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone

    HelloWorld();

    virtual bool init();  

    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* scene();

    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);

private:
    Size winSize;
    //这里添加一个回调方法
    void loadCallback1(AsyncTaskTime *time);

};

#endif // __HELLOWORLD_SCENE_H__

HelloWorldScene.cpp

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    auto as = AsyncTest::create();
    as->retain();
    as->addImageAsync("test", CC_CALLBACK_1(HelloWorld::loadCallback1, this));

    return true;
}

void HelloWorld::loadCallback1(AsyncTaskTime *time)
{

    log("加载完成");

}

控制台:

cocos2d: 加载完成

这样我们就将TextureCache中

virtual void addImageAsync(const
std::string &filepath,
const std::function<void(Texture2D*)>& callback);

这个异步加载数据的功能实现了。

时间: 2024-10-26 05:35:31

Cocos2d-x3.2 TextureCache类异步加载功能讲解的相关文章

Unity3D协同函数与异步加载功能实战 学习

图片异步加载

文章转载自:http://imziv.com/blog/article/read.htm?id=75 图片异步加载功能是现在web中非常常见的一个针对web做优化的方法.尤其是在移动端,面对大量的图片列表的时候,如果没有做相应的优化,会直接导致页面滑动和加载的卡顿,而且用户会莫名的发现当前应用占用的流量会很大,因为他可能都没有浏览到很多图片,而程序就自动加载了所以的图片,对于一个流量吃紧的人来讲,这个也是很讨厌的.所以实现按浏览需求加载时十分有必要的. 其实实现图片异步加载的核心思路十分简单,就

模仿SDWebImage实现异步加载图片

SDWebImage想必大家都不陌生吧,要实现它的图片异步加载功能这个还是很简单的. 注意:此处我只实现了异步加载图片,并没有将文件缓存到本地的打算哦:) 源码: UIImageView+YXImageView.h // // UIImageView+YXImageView.h // PicDemo // // Copyright (c) 2014年 Y.X. All rights reserved. // #import <UIKit/UIKit.h> @interface UIImageV

实现图片的异步加载

图片异步加载功能是现在web中非常常见的一个针对web做优化的方法.尤其是在移动端,面对大量的图片列表的时候,如果没有做相应的优化,会直接导致页面滑动和加载的卡顿,而且用户会莫名的发现当前应用占用的流量会很大,因为他可能都没有浏览到很多图片,而程序就自动加载了所以的图片,对于一个流量吃紧的人来讲,这个也是很讨厌的.所以实现按浏览需求加载时十分有必要的. 其实实现图片异步加载的核心思路十分简单,就是通过判断当图片元素是否出现在视窗范围内后,则去加载图片资源,否则不加载.所以我们需要首先解决判断im

基于jQuery的图片异步加载和预加载实例

如今的网页中有很多图片,比如相册列表,那么如果一次性读取图片将会瞬间加重服务器的负担,所以我们用jQuery来实现图片的异步加载和预加载功能,这样在页面的可视范围内才会加载图片,当拖动页面至可视界面时,其他图片才会加载,改插件很好地实现了图片异步加载功能. 在线预览   源码下载 html代码部分: <div id="content"> <div id="button"> <ul> <li>小图</li>

Android编程之图片(异步)加载类

应某人之请,写一篇关于图片加载类.其实,网上有很多这样的类,而且比较推崇的是来自google中开源中的一篇.他写的比较好了,而且注意了内存优化,下面贴出它的图片下载类: [java] view plaincopy /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not 

Android Asynchronous Http Client--Android 开源的网络异步加载类

整理Android Asynchronous Http Client的使用 Android Asynchronous Http Client(AHC) 一个回调式的Android网络请求库 概括: AHC是基于Apache的HttpClient 库,所有的网络请求过程在UI线程之外进行,而回调是在Handler里面处理.也可以再Service或者后台程序里面使用,这个库会自动识别并在相应的Context进行处理. 特点: 异步发送HTTP请求,在回调函数中处理响应 HTTP请求过程不在UI线程进

一个异步加载图片的公用类: EGOImageLoading

逛论坛的时候,发现偶尔还会有人在问怎么做图片的异步加载,很多回答都还是告知用原始的connection,收到数据NSData以后,再用UIImage initWithData生成图片对象.对于刚开始接触iOS开发的人来说,我还是推荐用这种方式的.但是对于已经有一定iOS开发经验的人来说,我推荐你们用比较成熟的第三方公用类.为什么这么说呢,1) 首先图片异步加载属于一个公共的问题空间,这部分的代码,对于所有需要加载网络图片的项目,逻辑都是一样的,也就是我们应     该把这部分代码做成可重用的,或

Unity+NGUI打造网络图片异步加载与本地缓存工具类(二)

接上文,我们的工具类中的主要方法: public  void SetAsyncImage(string url,UITexture texture) 按照前文分析的图片加载步骤来 public void SetAsyncImage(string url,UITexture texture){ //开始下载图片前,将UITexture的主图片设置为占位图 texture.mainTexture = placeholder; //判断是否是第一次加载这张图片 if (!File.Exists (pa