Вопрос или проблема
У меня есть приложение для экзаменов, где есть категория с идентификацией изображений, ничего особенного. Чтобы предотвратить увеличение размера приложения, я решил хранить изображения в Google Drive (это показалось мне лучшим решением, потому что я могу создать изображения на своем ПК, а затем немедленно и, что более важно, автоматически загрузить их на Drive). НО моя функция отображает только некоторые изображения, и всегда случайные. Представьте, у вас есть 10 вопросов викторины – первое изображение загружается, 2-е и 3-е нет, но 4-е да, и так далее. Всегда случайным образом. В следующий раз 1-е не загружается, но 2-е да, 3-е нет…
Код функции:
private void loadImage(String id, ImageView mainImage){
Glide.with(this)
.asBitmap()
.load(BASE_URL + id)
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontAnimate()
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
assert e != null;
for (Throwable t : e.getRootCauses()) {
Log.e("TAG", "Caused by", t);
}
e.logRootCauses("TAG");
return false;
}
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
Toast.makeText(getApplicationContext(), "Image ready!", Toast.LENGTH_LONG).show();
return false;
}
})
.into(mainImage);
}
BASE_URL является стандартным “https://docs.google.com/uc?id=”, а id извлекается как вопрос из массива
Ошибка Logcat:
E Caused by com.bumptech.glide.load.HttpException: Failed to connect or obtain data, status code: -1
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:98)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:122)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:58)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:95)
at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:88)
at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:311)
at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:277)
at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:235)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:421)
at java.lang.Thread.run(Thread.java:923)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultPriorityThreadFactory$1.run(GlideExecutor.java:380)
Caused by: java.net.SocketTimeoutException: timeout
at com.android.okhttp.okio.Okio$3.newTimeoutException(Okio.java:214)
at com.android.okhttp.okio.AsyncTimeout.exit(AsyncTimeout.java:263)
at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:217)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:307)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:301)
at com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:197)
at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:188)
at com.android.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:129)
at com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:750)
at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:622)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:475)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:248)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:211)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:30)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:95)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:122)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:58)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:95)
at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:88)
at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:311)
at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:277)
at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:235)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:421)
at java.lang.Thread.run(Thread.java:923)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultPriorityThreadFactory$1.run(GlideExecutor.java:380)
Caused by: java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
at java.net.SocketInputStream.read(SocketInputStream.java:176)
at java.net.SocketInputStream.read(SocketInputStream.java:144)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788)
at com.android.okhttp.okio.Okio$2.read(Okio.java:138)
at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:213)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:307)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:301)
at com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:197)
at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:188)
at com.android.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:129)
at com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:750)
at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:622)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:475)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:248)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:211)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:30)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:95)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:122)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:58)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
at com.bumptech.glide.load.engine.SourceGenerator.startNextLoad(SourceGenerator.java:95)
at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:88)
at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:311)
at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:277)
at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:235)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:421)
at java.lang.Thread.run(Thread.java:923)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultPriorityThreadFactory$1.run(GlideExecutor.java:380)
Я имею в виду код состояния -1? Я привык к исключениям Http 400-500, но -1? Я пытался разобраться в ошибке, но это слишком сложно для меня, я не так уж опытен в https и подобном.
Спасибо за любую помощь!
Ответ или решение
Проблема, с которой вы столкнулись при использовании библиотеки Glide для загрузки изображений из Google Drive, может быть связана с несколькими возможными причинами. При анализе ошибки и поведения вашего приложения полезно рассмотреть как технические детали, так и основные принципы работы с API и загрузкой изображений.
Причины проблемы
-
Неправильные URLs для изображений:
ИспользованиеBASE_URL = "https://docs.google.com/uc?id="
требует, чтобы идентификатор изображения (id
) был корректным и доступным. Убедитесь, что все ваши изображения имеют правильные ссылки и что эти изображения открыты для общего доступа. Если изображение недоступно по ссылке, Glide не сможет его загрузить. -
Настройки доступа к файлам Google Drive:
Убедитесь, что у всех изображений, которые вы пытаетесь загрузить, установлены правильные разрешения. Если изображения находятся в личной папке или имеют ограничения доступа, попробуйте установить доступ для всех, использующих ссылку. Это можно сделать в настройках общего доступа файла в Google Drive. -
Стратегия кеширования:
В вашем коде используется стратегия кешированияDiskCacheStrategy.NONE
, что означает, что Glide не будет кешировать загруженные изображения. Это может привести к увеличению числа запросов к Google Drive и в конечном итоге быть причиной ошибок при загрузке изображений. Рассмотрите возможность использования другой стратегии кеширования (например,DiskCacheStrategy.AUTOMATIC
), чтобы уменьшить количество запросов. -
Проблемы с сетью и таймауты:
ОшибкаSocketTimeoutException
свидетельствует о том, что приложение не смогло получить ответ от сервера в установленный период времени. Проверьте своё интернет-соединение и настройте таймауты в Glide. Вы можете задать свои значения таймаутов, используя настройкиOkHttpClient
.
Рекомендации по исправлению
-
Проверка доступа к файлам:
Убедитесь, что все необходимые изображения общедоступны по ссылке. Для этого проверьте настройки доступа в Google Drive. -
Логи и обработка ошибок:
Добавьте дополнительные логи в ваше приложение, чтобы лучше понять, какие именно идентификаторы не загружаются. Попробуйте реализовать показ ошибок более наглядно для пользователей (например, при загрузке ошибок показывать уведомление). -
Эффективная обработка изображений с Glide:
Рассмотрите следующие улучшения в вашем коде:private void loadImage(String id, ImageView mainImage) { Glide.with(this) .asBitmap() .load(BASE_URL + id) .fitCenter() .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) // Поменяйте на AUTOMATIC или ALL .timeout(10000) // Установите таймаут в 10 секунд .listener(new RequestListener<Bitmap>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { if (e != null) { Log.e("TAG", "Error loading image", e); } return false; // Возврат false для выполнения дальнейшей обработки } @Override public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { Toast.makeText(getApplicationContext(), "Image loaded successfully!", Toast.LENGTH_SHORT).show(); return false; // Возврат false для выполнения дальнейшей обработки } }) .into(mainImage); }
Заключение
Следуя данным рекомендациям, вы сможете существенно улучшить стабильность загрузки изображений и избежать случайных ошибок в вашем приложении. Проверьте доступы и настройте код, используя информацию из логов. Если ошибка продолжает появляться, подумайте о более детальных логах или даже об обходных путях, таких как предварительное кеширование изображений на устройстве.