diff --git a/include/AvatarProvider.h b/include/AvatarProvider.h
index dabd609c7e0f58f9e461880fb50cc786a8f1b246..fd5f15c457c367b4dea94266fad262e3e99e4a33 100644
--- a/include/AvatarProvider.h
+++ b/include/AvatarProvider.h
@@ -24,23 +24,26 @@
 
 class MatrixClient;
 class TimelineItem;
+class Cache;
 
 class AvatarProvider : public QObject
 {
         Q_OBJECT
 
 public:
-        static void init(QSharedPointer<MatrixClient> client) { client_ = client; }
+        static void init(QSharedPointer<MatrixClient> client, QSharedPointer<Cache> cache)
+        {
+                client_ = client;
+                cache_  = cache;
+        }
         //! The callback is called with the downloaded avatar for the given user
         //! or the avatar is downloaded first and then saved for re-use.
         static void resolve(const QString &room_id,
                             const QString &userId,
                             QObject *receiver,
                             std::function<void(QImage)> callback);
-        //! Remove all saved data.
-        static void clear() { avatars_.clear(); };
 
 private:
         static QSharedPointer<MatrixClient> client_;
-        static QHash<QString, QImage> avatars_;
+        static QSharedPointer<Cache> cache_;
 };
diff --git a/include/ChatPage.h b/include/ChatPage.h
index b3b379cb72c07374b8142ec9997035ad6a9e4f6f..d0be9ce1d77433ad75f05e40a54b9dcc9060e660 100644
--- a/include/ChatPage.h
+++ b/include/ChatPage.h
@@ -51,8 +51,8 @@ constexpr int CONSENSUS_TIMEOUT      = 1000;
 constexpr int SHOW_CONTENT_TIMEOUT   = 3000;
 constexpr int TYPING_REFRESH_TIMEOUT = 10000;
 
-Q_DECLARE_METATYPE(mtx::responses::Rooms);
-Q_DECLARE_METATYPE(std::vector<std::string>);
+Q_DECLARE_METATYPE(mtx::responses::Rooms)
+Q_DECLARE_METATYPE(std::vector<std::string>)
 
 class ChatPage : public QWidget
 {
diff --git a/src/AvatarProvider.cc b/src/AvatarProvider.cc
index 9f861fdb6ab9bd0be7e01aa626276c18b46a73b8..c77452396979e540f7c253c57c54491dd5b7d4e5 100644
--- a/src/AvatarProvider.cc
+++ b/src/AvatarProvider.cc
@@ -15,12 +15,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <QBuffer>
+#include <QtConcurrent>
+
 #include "AvatarProvider.h"
 #include "Cache.h"
 #include "MatrixClient.h"
 
 QSharedPointer<MatrixClient> AvatarProvider::client_;
-QHash<QString, QImage> AvatarProvider::avatars_;
+QSharedPointer<Cache> AvatarProvider::cache_;
 
 void
 AvatarProvider::resolve(const QString &room_id,
@@ -28,21 +31,22 @@ AvatarProvider::resolve(const QString &room_id,
                         QObject *receiver,
                         std::function<void(QImage)> callback)
 {
-        const auto key = QString("%1 %2").arg(room_id).arg(user_id);
+        const auto key       = QString("%1 %2").arg(room_id).arg(user_id);
+        const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
 
-        if (!Cache::AvatarUrls.contains(key))
+        if (!Cache::AvatarUrls.contains(key) || cache_.isNull())
                 return;
 
-        if (avatars_.contains(key)) {
-                auto img = avatars_[key];
+        if (avatarUrl.isEmpty())
+                return;
 
-                if (!img.isNull()) {
-                        callback(img);
-                        return;
-                }
+        auto data = cache_->image(avatarUrl);
+        if (!data.isNull()) {
+                callback(QImage::fromData(data));
+                return;
         }
 
-        auto proxy = client_->fetchUserAvatar(Cache::avatarUrl(room_id, user_id));
+        auto proxy = client_->fetchUserAvatar(avatarUrl);
 
         if (proxy.isNull())
                 return;
@@ -50,9 +54,16 @@ AvatarProvider::resolve(const QString &room_id,
         connect(proxy.data(),
                 &DownloadMediaProxy::avatarDownloaded,
                 receiver,
-                [user_id, proxy, callback, key](const QImage &img) {
+                [user_id, proxy, callback, avatarUrl](const QImage &img) {
                         proxy->deleteLater();
-                        avatars_.insert(key, img);
+                        QtConcurrent::run([img, avatarUrl]() {
+                                QByteArray data;
+                                QBuffer buffer(&data);
+                                buffer.open(QIODevice::WriteOnly);
+                                img.save(&buffer, "PNG");
+
+                                cache_->saveImage(avatarUrl, data);
+                        });
                         callback(img);
                 });
 }
diff --git a/src/Cache.cc b/src/Cache.cc
index 2afd3080b14db15b447e8b864a81d77825f699a3..1155a40a1b9485823de4c1624792876faed150da 100644
--- a/src/Cache.cc
+++ b/src/Cache.cc
@@ -144,6 +144,9 @@ Cache::saveImage(const QString &url, const QByteArray &image)
 QByteArray
 Cache::image(const QString &url) const
 {
+        if (url.isEmpty())
+                return QByteArray();
+
         auto key = url.toUtf8();
 
         try {
@@ -160,7 +163,7 @@ Cache::image(const QString &url) const
 
                 return QByteArray(image.data(), image.size());
         } catch (const lmdb::error &e) {
-                qCritical() << "image:" << e.what();
+                qCritical() << "image:" << e.what() << url;
         }
 
         return QByteArray();
diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index a37cc9f0d1f5669c9f5824345c13508f8ef63fc9..280ae399ac3a678f71d9d8eb280f271f7b7377f5 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -399,8 +399,6 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client,
                 this,
                 &ChatPage::setGroupViewState);
 
-        AvatarProvider::init(client);
-
         connect(this, &ChatPage::continueSync, this, [this](const QString &next_batch) {
                 syncTimeoutTimer_->start(SYNC_RETRY_TIMEOUT);
                 client_->setNextBatchToken(next_batch);
@@ -461,7 +459,6 @@ ChatPage::resetUI()
         top_bar_->reset();
         user_info_widget_->reset();
         view_manager_->clearAll();
-        AvatarProvider::clear();
 
         showUnreadMessageNotification(0);
 }
@@ -497,6 +494,8 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
         room_list_->setCache(cache_);
         text_input_->setCache(cache_);
 
+        AvatarProvider::init(client_, cache_);
+
         try {
                 cache_->setup();
 
@@ -584,21 +583,30 @@ ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_na
         user_info_widget_->setUserId(userid);
         user_info_widget_->setDisplayName(display_name);
 
-        if (avatar_url.isValid()) {
-                auto proxy = client_->fetchUserAvatar(avatar_url);
+        if (!avatar_url.isValid())
+                return;
 
-                if (proxy.isNull())
+        if (!cache_.isNull()) {
+                auto data = cache_->image(avatar_url.toString());
+                if (!data.isNull()) {
+                        user_info_widget_->setAvatar(QImage::fromData(data));
                         return;
-
-                proxy->setParent(this);
-                connect(proxy.data(),
-                        &DownloadMediaProxy::avatarDownloaded,
-                        this,
-                        [this, proxy](const QImage &img) {
-                                proxy->deleteLater();
-                                user_info_widget_->setAvatar(img);
-                        });
+                }
         }
+
+        auto proxy = client_->fetchUserAvatar(avatar_url);
+
+        if (proxy.isNull())
+                return;
+
+        proxy->setParent(this);
+        connect(proxy.data(),
+                &DownloadMediaProxy::avatarDownloaded,
+                this,
+                [this, proxy](const QImage &img) {
+                        proxy->deleteLater();
+                        user_info_widget_->setAvatar(img);
+                });
 }
 
 void
@@ -661,8 +669,8 @@ ChatPage::loadStateFromCache()
                 try {
                         cache_->populateMembers();
 
-                        emit initializeRoomList(cache_->roomInfo());
                         emit initializeEmptyViews(cache_->joinedRooms());
+                        emit initializeRoomList(cache_->roomInfo());
                 } catch (const lmdb::error &e) {
                         std::cout << "load cache error:" << e.what() << '\n';
                         // TODO Clear cache and restart.
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 17a34d968fd67e5a34d625f46d40bf6aa24ffb2c..e95f8b970e58bde4cef20aec5de013b9c075abf5 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -621,6 +621,9 @@ MatrixClient::fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url)
 void
 MatrixClient::fetchCommunityAvatar(const QString &communityId, const QUrl &avatar_url)
 {
+        if (avatar_url.isEmpty())
+                return;
+
         QList<QString> url_parts = avatar_url.toString().split("mxc://");
 
         if (url_parts.size() != 2) {