Кэшируем картинки

Задача: в приложении много картинок, очень много и их надо как то уметь кешировать? Что же делать? Будем их складывать на диск!
Кэшируем картинки

Сперва подготовим класс, назовём его например CacheAdapter

Код CPP-QT:
  1. CacheAdapter::CacheAdapter(QObject *parent) :
  2. QObject(parent)
  3. {
  4. cache_prefix = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+"/cache"; //ОБРАТИТЕ ТУТ ВНИМАНИЕ - Используем класс QStandardPaths - не надо писать прямые пути!
  5. cache_dir = QDir(cache_prefix);
  6.  
  7. m_cacheSize = 200*1024*2024; //Размер кеша в байтах. Тут 200 по моему
  8. m_liveTime = 7*24*60*60; //Время жизни кеша в днях. Тут их 7
  9.  
  10. QList<QString> ext;
  11. ext << "jpg" << "jpeg" << "png"; //определяем что будем кешировать, мне нужны были только картинки
  12. this->setAllowedExt(ext);
  13.  
  14. //Тут стандартные проверки на первый запуск.
  15. if(!cache_dir.exists())
  16. {
  17. cache_dir.mkpath(cache_prefix);
  18. }
  19. else
  20. {
  21. this->cleanCache(); //Об этом мы поговорим чуть попозжее.
  22. }
  23. }
Ну тут всё я думаю просто: Определяем параметры кеша(да я знаю надо перенести в QSettings но я думаю вы это сделаете без меня), говорим что кешировать и куда складывать. Если папочки нет то создаём её. Всё просто.
Далее получаем сам файл. Делать это надо красиво:
Код CPP-QT:
  1. void CacheAdapter::getFile(QString url)
  2. {
  3. //Определяем разшерение файла - опять таки сделано кривовато. Но для понимания работы сойдёт.
  4. QString fileExt=url.split(".",QString::SkipEmptyParts).last().toLower(); // заметье мы привели сразу же всё к нижнему регистру чтобы не париться с PNG Png png
  5. //if file extension not allow return url
  6. if(!m_allowedExt.contains(fileExt))
  7. {
  8. emit ready(url);
  9. }
  10.  
  11. //имя кешированного файла сделаем на основе md5 его урла
  12. QString fileName = QString(QCryptographicHash::hash(url.toUtf8(),QCryptographicHash::Md5).toHex());
  13. //всё склеиваем вместе
  14. m_cacheFileFullPath = cache_prefix+"/"+fileName+"."+fileExt;
  15. QFile cacheFile(m_cacheFileFullPath);
  16. //Вот тут первая часть магии: Если файл такой уже есть, то мы подаём сигнал мол всё ок - заберай.
  17. if(cacheFile.exists())
  18. {
  19. emit ready(m_cacheFileFullPath);
  20. }
  21. //А если его нет, то скачиваем, причём посмотите, качаем красиво!
  22. else
  23. {
  24. QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
  25. //При готовности отправляемся в слот сохранения
  26. QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileCopy(QNetworkReply*)));
  27. //В процессе говорим сколько процентов осталось
  28. QObject::connect(reply,SIGNAL(downloadProgress(qint64, qint64)),this, SLOT(updateDownloadProgress(qint64, qint64)));
  29. }
  30. }
Процесс копирования файла тривиален:
Код CPP-QT:
  1. void CacheAdapter::fileCopy(QNetworkReply *reply)
  2. {
  3. QFile cacheFile(m_cacheFileFullPath);
  4. if(cacheFile.open(QFile::WriteOnly))
  5. {
  6. cacheFile.write(reply->readAll());
  7. cacheFile.flush();
  8. cacheFile.close();
  9.  
  10. emit ready(cacheFile.fileName());
  11. }
  12. //тут бы добавить про else и обработчик ошибок, но ты же умный программист и справишься сам? ;)
  13. }
И конечно красивость: прогрессбар мы тоже оформим, чуть по позжее
Код CPP-QT:
  1. void CacheAdapter::updateDownloadProgress(qint64 read, qint64 total)
  2. {
  3. emit readyProgress(read*100/total);
  4. }
А теперь наши шаловливые ручки запихнут всё это в QML чтобы было круто аж до визгу.
Первый пункт: идём в main.cpp и регистрируем новый тип.
Код CPP-QT:
  1. qmlRegisterType<CacheAdapter>("cacheArapter",1,0,"CacheAdapter");
В том месте где у нас много картинок, а я сделал просто отдельный компонент, но не суть, берём вставляем наш код:
Код QML:
  1. Component.onCompleted: {
  2. cacheAdaprer.getFile(image_url);
  3. }
  4.  
  5. CacheAdapter{
  6. id: cacheAdaprer
  7. }
Компоненту сказали - дёргай файл по урлу. И всё сигналы связываем вместе:
Код QML:
  1. target: cacheAdaprer
  2. onReady:{
  3. mainImage.source = "file://"+url
  4. loadingBar.visible = false
  5. }
  6. onReadyProgress:{
  7. loadingBar.value = progress;
  8. }
  9. }
Тут думаю тоже всё понятно. Если нет, то пиши в комменты.
А теперь вежливость: не гоже гадить пользователям на устройстве, особенно на мобильном. Правильнее будет чистить за собой:
Код CPP-QT:
  1. void CacheAdapter::cleanCache()
  2. {
  3. // Если нам пофиг на пользователей то сразу возвращаемся
  4. if(m_cacheSize == 0 || m_liveTime == 0)
  5. {
  6. return;
  7. }
  8. // получаем список файлов в нашей директории. Мы срём без подкатологов так что тут просто
  9. cache_dir.setFilter(QDir::Files);
  10. QStringList c_files = cache_dir.entryList();
  11.  
  12. int time = QDateTime::currentMSecsSinceEpoch();
  13. int filesSize = 0;
  14. // Пробегаемся по всем файлам и удаляем те которые уже протухли
  15. foreach(const QFile &file, c_files){
  16. QFileInfo fileInfo(cache_prefix+"/"+file.fileName());
  17. //Check livetime
  18. int liveTime = time-fileInfo.created().toMSecsSinceEpoch();
  19. if(liveTime > m_liveTime)
  20. {
  21. file.remove(cache_prefix+"/"+file.fileName());
  22. }
  23. else
  24. {
  25. filesSize = filesSize+fileInfo.size();
  26. }
  27. }
  28. //Проверяем размер директории
  29. if(filesSize > m_cacheSize)
  30. {
  31. //А как ты напишешь функцию проверки кеша на размер? Пиши в комментариях :)))
  32. }
  33. }
Если нужны готовые классы и вам лень дописать всё остальное - пишите в комментариях куда всё скинуть.
Комментарии (0)

Нет комментариев. Ваш будет первым!

Copyright 2016-2024 NeoChapay