RecyclerView, загрузка изображений с сервера. Вопросы по архитектуре приложения

Распространенная задача: есть путь к серверу http://my_site.com/images где хранятся изображения в высоком качестве image_000.jpg...image_200.jpg, нужно организовать работу с этими изображениями: вывести миниатюры в RecyclerView а по "тапу" на пункте загрузить его в локальное хранилище. С такой задачей не сталкивался и хотел уточнить несколько моментов у более опытных программистов.

  1. Определение количества изображений. Хотелось бы просто добавлять новые, а клиент должен подхватить это "на лету". Мое решение: просто web страница с количеством изображений (загружаем, "парсим", получаем).
  2. Миниатюры изображений. Делать несколько миниатюр для каждого вида разрешений (mdpi, hdpi ... xxxhdpi) или ограничиться одним, или отдавать сервером "на лету"?
  3. Стратегия загрузки миниатюр в локальное хранилище: грузить сразу при старте или по мере необходимости в Adapter'е. Очень не хотел бы использовать сторонние библиотеки. Планирую загружать миниатюры в AsyncTask при помощи HttpURLConnection, а само изображение через DownloadManager.

Буду рад любым подсказкам и направлениям, и конечно примерам.


Ответы (1 шт):

Автор решения: Sh4rx

Могу подсказать насчет загрузки превьюх без библиотек. Когда-то писал такой код, но конечно же он уже устаревший.

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ThumbnailDownloader<T> extends HandlerThread {
   private static final String TAG = "ThumbnailDownloader";
   private static final int MESSAGE_DOWNLOAD = 0;

   private boolean mHasQuit = false;
   private Handler mRequestHandler;
   private ConcurrentMap<T,String> mRequestMap = new ConcurrentHashMap<>();
   private Handler mResponseHandler;
   private ThumbnailDownloadListener<T> mThumbnailDownloadListener;

   public interface ThumbnailDownloadListener<T>{
       void onThumbnailDownloaded(T target, Bitmap thumbnail);
   }

   public void setThumbnailDownloadListener(ThumbnailDownloadListener<T> listener){
       mThumbnailDownloadListener = listener;
    }

    public ThumbnailDownloader(Handler responseHandler) {
        super(TAG);
        mResponseHandler = responseHandler;
    }

    @Override
    protected void onLooperPrepared() {
        mRequestHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == MESSAGE_DOWNLOAD){
                    T target = (T) msg.obj;
                    Log.i(TAG, "Got a request for URL: " + mRequestMap.get(target));
                    handleRequest(target);
                }
            }
        };

    }



    @Override
    public boolean quit() {
        mHasQuit = true;
        return super.quit();
    }

    public void queueThumbnail(T target, String url){
        Log.i(TAG, "Got a URL: " + url);

        if (url == null){
            mRequestMap.remove(target);
        } else {
          mRequestMap.put(target, url);
          mRequestHandler.obtainMessage(MESSAGE_DOWNLOAD, target)
                  .sendToTarget();
        }
    }

    public void clearQueue(){
       mRequestHandler.removeMessages(MESSAGE_DOWNLOAD);
       mRequestMap.clear();
    }

    private void handleRequest(final T target) {
        try {
            final String url = mRequestMap.get(target);
            if (url == null){
                return;
            }

            byte [] bitmapBytes = new MyFetcher().getUrlBytes(url);
            final Bitmap bitmap = BitmapFactory
                    .decodeByteArray(bitmapBytes, 0 , bitmapBytes.length);
            Log.i(TAG, "Bitmap created");

            mResponseHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mRequestMap.get(target) != url || mHasQuit){
                       return;
                    }
                    mRequestMap.remove(target);
                    mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmap);
                }
            });
        } catch (IOException ioe){
            Log.e(TAG, "Error downloading image", ioe);
        }


    }
}

и в активити/фрагменте

   private ThumbnailDownloader<PhotoHolder> mThumbnailDownloader;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        setHasOptionsMenu(true);

        Handler responseHandler = new Handler();
        mThumbnailDownloader = new ThumbnailDownloader<>(responseHandler);
        mThumbnailDownloader.setThumbnailDownloadListener(new ThumbnailDownloader.ThumbnailDownloadListener<PhotoHolder>() {
            @Override
            public void onThumbnailDownloaded(PhotoHolder photoHolder, Bitmap bitmap) {
                Drawable drawable = new BitmapDrawable(getResources(), bitmap);
                photoHolder.bindDrawable(drawable);
            }
        });
        mThumbnailDownloader.start();
        mThumbnailDownloader.getLooper();
        Log.i(TAG, "Background thread started");


    }

Если надо, могу скинуть ссылку на проект, правда скажу что писалось это несколько лет назад и код уже устаревший)

→ Ссылка