RecyclerView, загрузка изображений с сервера. Вопросы по архитектуре приложения
Распространенная задача: есть путь к серверу http://my_site.com/images где хранятся изображения в высоком качестве image_000.jpg...image_200.jpg, нужно организовать работу с этими изображениями: вывести миниатюры в RecyclerView а по "тапу" на пункте загрузить его в локальное хранилище. С такой задачей не сталкивался и хотел уточнить несколько моментов у более опытных программистов.
- Определение количества изображений. Хотелось бы просто добавлять новые, а клиент должен подхватить это "на лету". Мое решение: просто web страница с количеством изображений (загружаем, "парсим", получаем).
- Миниатюры изображений. Делать несколько миниатюр для каждого вида разрешений (mdpi, hdpi ... xxxhdpi) или ограничиться одним, или отдавать сервером "на лету"?
- Стратегия загрузки миниатюр в локальное хранилище: грузить сразу при старте или по мере необходимости в Adapter'е.
Очень не хотел бы использовать сторонние библиотеки.
Планирую загружать миниатюры в
AsyncTaskпри помощиHttpURLConnection, а само изображение черезDownloadManager.
Буду рад любым подсказкам и направлениям, и конечно примерам.
Ответы (1 шт):
Могу подсказать насчет загрузки превьюх без библиотек. Когда-то писал такой код, но конечно же он уже устаревший.
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");
}
Если надо, могу скинуть ссылку на проект, правда скажу что писалось это несколько лет назад и код уже устаревший)