ListView
를 사용하여 해당 이미지와 관련된 일부 이미지 및 캡션을 표시하고 있습니다. 인터넷에서 이미지를 가져오고 있습니다. 텍스트가 표시되는 동안 UI가 차단되지 않고 이미지가 다운로드될 때 이미지가 표시되도록 이미지를 지연 로드하는 방법이 있습니까?
총 이미지 수는 고정되어 있지 않습니다.
질문자 :lostInTransit
ListView
를 사용하여 해당 이미지와 관련된 일부 이미지 및 캡션을 표시하고 있습니다. 인터넷에서 이미지를 가져오고 있습니다. 텍스트가 표시되는 동안 UI가 차단되지 않고 이미지가 다운로드될 때 이미지가 표시되도록 이미지를 지연 로드하는 방법이 있습니까?
총 이미지 수는 고정되어 있지 않습니다.
다음은 내 앱이 현재 표시하고 있는 이미지를 보관하기 위해 만든 것입니다. 여기서 사용 중인 "Log" 개체는 Android 내부의 최종 Log 클래스에 대한 사용자 정의 래퍼입니다.
package com.wilson.android.library; /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import java.io.IOException; public class DrawableManager { private final Map<String, Drawable> drawableMap; public DrawableManager() { drawableMap = new HashMap<String, Drawable>(); } public Drawable fetchDrawable(String urlString) { if (drawableMap.containsKey(urlString)) { return drawableMap.get(urlString); } Log.d(this.getClass().getSimpleName(), "image url:" + urlString); try { InputStream is = fetch(urlString); Drawable drawable = Drawable.createFromStream(is, "src"); if (drawable != null) { drawableMap.put(urlString, drawable); Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", " + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", " + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth()); } else { Log.w(this.getClass().getSimpleName(), "could not get thumbnail"); } return drawable; } catch (MalformedURLException e) { Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); return null; } catch (IOException e) { Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); return null; } } public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { if (drawableMap.containsKey(urlString)) { imageView.setImageDrawable(drawableMap.get(urlString)); } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageView.setImageDrawable((Drawable) message.obj); } }; Thread thread = new Thread() { @Override public void run() { //TODO : set imageView to a "pending" image Drawable drawable = fetchDrawable(urlString); Message message = handler.obtainMessage(1, drawable); handler.sendMessage(message); } }; thread.start(); } private InputStream fetch(String urlString) throws MalformedURLException, IOException { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpGet request = new HttpGet(urlString); HttpResponse response = httpClient.execute(request); return response.getEntity().getContent(); } }
이미지와 함께 게으른 목록(GitHub에 있음) 의 간단한 데모를 만들었습니다.
기본 사용법
ImageLoader imageLoader=new ImageLoader(context); ... imageLoader.DisplayImage(url, imageView);
AndroidManifest.xml에 다음 권한을 추가하는 것을 잊지 마십시오.
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Please
ImageLoader의 인스턴스를 하나만 생성하고 애플리케이션 전체에서 재사용합니다. 이렇게 하면 이미지 캐싱이 훨씬 더 효율적입니다.
누군가에게 도움이 될 수 있습니다. 백그라운드 스레드에서 이미지를 다운로드합니다. 이미지가 SD 카드와 메모리에 캐시되고 있습니다. 캐시 구현은 매우 간단하며 데모용으로 충분합니다. 메모리 소비를 줄이기 위해 inSampleSize로 이미지를 디코딩합니다. 또한 재활용된 뷰를 올바르게 처리하려고 노력합니다.
오픈 소스 도구 Universal Image Loader를 추천 합니다. 원래 Fedor Vlasov의 프로젝트 LazyList를 기반으로 했으며 그 이후로 크게 개선되었습니다.
Multithreading For Performance , Gilles Debunne의 자습서.
이것은 Android 개발자 블로그에서 가져온 것입니다. 제안된 코드는 다음을 사용합니다.
AsyncTasks
.FIFO cache
.garbage collect
-ed 캐시.Drawable
업데이트: 이 답변은 현재 매우 비효율적입니다. Garbage Collector는 SoftReference 및 WeakReference에서 적극적으로 작동하므로 이 코드는 새 앱에 적합하지 않습니다. (대신 다른 답변에서 제안한 Universal Image Loader 와 같은 라이브러리를 사용해 보십시오.)
코드를 제공한 James와 SoftReference 사용을 제안한 Bao-Long에게 감사드립니다. James의 코드에 SoftReference 변경 사항을 구현했습니다. 불행히도 SoftReferences로 인해 내 이미지가 너무 빨리 가비지 수집되었습니다. 제 경우에는 목록 크기가 제한되어 있고 이미지가 작기 때문에 SoftReference 항목 없이는 괜찮았습니다.
1년 전 SoftReferences on google groups: link to thread 에 대한 토론이 있습니다. 너무 이른 가비지 수집에 대한 해결책으로 dalvik.system.VMRuntime.setMinimumHeapSize()를 사용하여 VM 힙 크기를 수동으로 설정할 수 있는 가능성을 제안하는데, 이는 그다지 매력적이지 않습니다.
public DrawableManager() { drawableMap = new HashMap<String, SoftReference<Drawable>>(); } public Drawable fetchDrawable(String urlString) { SoftReference<Drawable> drawableRef = drawableMap.get(urlString); if (drawableRef != null) { Drawable drawable = drawableRef.get(); if (drawable != null) return drawable; // Reference has expired so remove the key from drawableMap drawableMap.remove(urlString); } if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "image url:" + urlString); try { InputStream is = fetch(urlString); Drawable drawable = Drawable.createFromStream(is, "src"); drawableRef = new SoftReference<Drawable>(drawable); drawableMap.put(urlString, drawableRef); if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", " + drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", " + drawable.getMinimumHeight() + "," + drawable.getMinimumWidth()); return drawableRef.get(); } catch (MalformedURLException e) { if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); return null; } catch (IOException e) { if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e); return null; } } public void fetchDrawableOnThread(final String urlString, final ImageView imageView) { SoftReference<Drawable> drawableRef = drawableMap.get(urlString); if (drawableRef != null) { Drawable drawable = drawableRef.get(); if (drawable != null) { imageView.setImageDrawable(drawableRef.get()); return; } // Reference has expired so remove the key from drawableMap drawableMap.remove(urlString); } final Handler handler = new Handler() { @Override public void handleMessage(Message message) { imageView.setImageDrawable((Drawable) message.obj); } }; Thread thread = new Thread() { @Override public void run() { //TODO : set imageView to a "pending" image Drawable drawable = fetchDrawable(urlString); Message message = handler.obtainMessage(1, drawable); handler.sendMessage(message); } }; thread.start(); }
피카소
Jake Wharton의 Picasso 라이브러리를 사용하십시오. (ActionBarSherlock 개발자의 완벽한 ImageLoading 라이브러리)
Android용 강력한 이미지 다운로드 및 캐싱 라이브러리.
이미지는 Android 애플리케이션에 꼭 필요한 컨텍스트와 시각적 감각을 추가합니다. Picasso를 사용하면 종종 한 줄의 코드로 애플리케이션에서 번거로움 없이 이미지를 로드할 수 있습니다!
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Android에서 이미지를 로드할 때 발생하는 많은 일반적인 함정은 Picasso에서 자동으로 처리됩니다.
어댑터에서 ImageView 재활용 및 다운로드 취소 처리. 최소한의 메모리 사용으로 복잡한 이미지 변환. 자동 메모리 및 디스크 캐싱.
활주
Glide는 미디어 디코딩, 메모리 및 디스크 캐싱, 리소스 풀링을 간단하고 사용하기 쉬운 인터페이스로 래핑하는 Android용 빠르고 효율적인 오픈 소스 미디어 관리 프레임워크입니다.
Glide는 비디오 스틸, 이미지 및 애니메이션 GIF 가져오기, 디코딩 및 표시를 지원합니다. Glide에는 개발자가 거의 모든 네트워크 스택에 연결할 수 있는 유연한 API가 포함되어 있습니다. 기본적으로 Glide는 사용자 지정 HttpUrlConnection 기반 스택을 사용하지만 대신 Google의 Volley 프로젝트 또는 Square의 OkHttp 라이브러리에 대한 유틸리티 라이브러리 플러그인을 포함합니다.
Glide.with(this).load("your-url-here").into(imageView);
Glide의 주요 초점은 모든 종류의 이미지 목록을 최대한 부드럽고 빠르게 스크롤하는 것이지만 Glide는 원격 이미지를 가져오고, 크기를 조정하고, 표시해야 하는 거의 모든 경우에 효과적입니다.
페이스북 프레스코
Fresco는 Android 애플리케이션에서 이미지를 표시하기 위한 강력한 시스템입니다.
Fresco는 이미지 로드 및 표시를 처리하므로 필요하지 않습니다. 네트워크, 로컬 저장소 또는 로컬 리소스에서 이미지를 로드하고 이미지가 도착할 때까지 자리 표시자를 표시합니다. 두 가지 수준의 캐시가 있습니다. 하나는 메모리에, 다른 하나는 내부 저장소에 있습니다.
Android 4.x 이하에서 Fresco는 Android 메모리의 특정 영역에 이미지를 저장합니다. 이렇게 하면 애플리케이션이 더 빨리 실행되고 두려운 OutOfMemoryError가 훨씬 덜 자주 발생합니다.
고성능 로더 - 여기에 제안된 방법을 검토한 후 Ben의 솔루션 을 약간 변경하여 사용했습니다.
드로어블 작업이 비트맵보다 빠르다는 것을 깨달았기 때문에 드로어블을 대신 사용합니다.
SoftReference를 사용하면 좋지만 캐시된 이미지를 너무 자주 삭제하게 되므로 미리 정의된 크기에 도달할 때까지 이미지가 삭제되지 않도록 이미지 참조를 보유하는 연결 목록을 추가했습니다.
InputStream을 열려면 웹 캐시를 사용할 수 있는 java.net.URLConnection을 사용했습니다(먼저 응답 캐시를 설정해야 하지만 그건 다른 이야기입니다).
내 코드:
import java.util.Map; import java.util.HashMap; import java.util.LinkedList; import java.util.Collections; import java.util.WeakHashMap; import java.lang.ref.SoftReference; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import android.graphics.drawable.Drawable; import android.widget.ImageView; import android.os.Handler; import android.os.Message; import java.io.InputStream; import java.net.MalformedURLException; import java.io.IOException; import java.net.URL; import java.net.URLConnection; public class DrawableBackgroundDownloader { private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>(); private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> (); private ExecutorService mThreadPool; private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); public static int MAX_CACHE_SIZE = 80; public int THREAD_POOL_SIZE = 3; /** * Constructor */ public DrawableBackgroundDownloader() { mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); } /** * Clears all instance data and stops running threads */ public void Reset() { ExecutorService oldThreadPool = mThreadPool; mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE); oldThreadPool.shutdownNow(); mChacheController.clear(); mCache.clear(); mImageViews.clear(); } public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) { mImageViews.put(imageView, url); Drawable drawable = getDrawableFromCache(url); // check in UI thread, so no concurrency issues if (drawable != null) { //Log.d(null, "Item loaded from mCache: " + url); imageView.setImageDrawable(drawable); } else { imageView.setImageDrawable(placeholder); queueJob(url, imageView, placeholder); } } private Drawable getDrawableFromCache(String url) { if (mCache.containsKey(url)) { return mCache.get(url).get(); } return null; } private synchronized void putDrawableInCache(String url,Drawable drawable) { int chacheControllerSize = mChacheController.size(); if (chacheControllerSize > MAX_CACHE_SIZE) mChacheController.subList(0, MAX_CACHE_SIZE/2).clear(); mChacheController.addLast(drawable); mCache.put(url, new SoftReference<Drawable>(drawable)); } private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) { /* Create handler in UI thread. */ final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { String tag = mImageViews.get(imageView); if (tag != null && tag.equals(url)) { if (imageView.isShown()) if (msg.obj != null) { imageView.setImageDrawable((Drawable) msg.obj); } else { imageView.setImageDrawable(placeholder); //Log.d(null, "fail " + url); } } } }; mThreadPool.submit(new Runnable() { @Override public void run() { final Drawable bmp = downloadDrawable(url); // if the view is not visible anymore, the image will be ready for next time in cache if (imageView.isShown()) { Message message = Message.obtain(); message.obj = bmp; //Log.d(null, "Item downloaded: " + url); handler.sendMessage(message); } } }); } private Drawable downloadDrawable(String url) { try { InputStream is = getInputStream(url); Drawable drawable = Drawable.createFromStream(is, url); putDrawableInCache(url,drawable); return drawable; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } private InputStream getInputStream(String urlString) throws MalformedURLException, IOException { URL url = new URL(urlString); URLConnection connection; connection = url.openConnection(); connection.setUseCaches(true); connection.connect(); InputStream response = connection.getInputStream(); return response; } }
저는 이 Android 교육을 따랐고 기본 UI를 차단하지 않고 이미지를 다운로드하는 데 탁월한 역할을 한다고 생각합니다. 또한 캐싱 및 많은 이미지 스크롤 처리도 처리합니다. 큰 비트맵을 효율적으로 로드
1. Picasso를 사용하면 응용 프로그램에서 종종 한 줄의 코드로 번거로움 없이 이미지를 로드할 수 있습니다!
Gradle 사용:
implementation 'com.squareup.picasso:picasso:(insert latest version)'
단 한 줄의 코드!
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
2. Glide 부드러운 스크롤링에 중점을 둔 Android용 이미지 로딩 및 캐싱 라이브러리
Gradle 사용:
repositories { mavenCentral() google() } dependencies { implementation 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' }
// 간단한 보기의 경우:
Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);
3. fresco 는 Android 애플리케이션에서 이미지를 표시하기 위한 강력한 시스템입니다. Fresco는 이미지 로드 및 표시를 처리하므로 필요하지 않습니다.
목록 보기에서 이미지를 지연 로드하는 방법을 설명하는 자습서를 작성했습니다. 재활용 및 동시성 문제에 대해 자세히 설명합니다. 또한 많은 스레드가 생성되는 것을 방지하기 위해 고정 스레드 풀을 사용합니다.
내가 하는 방법은 스레드를 시작하여 백그라운드에서 이미지를 다운로드하고 각 목록 항목에 대한 콜백을 전달하는 것입니다. 이미지 다운로드가 완료되면 목록 항목에 대한 보기를 업데이트하는 콜백을 호출합니다.
그러나 이 방법은 보기를 재활용할 때 잘 작동하지 않습니다.
XML Adapters라는 좋은 예를 하나 더 추가하고 싶습니다. Google에서 사용하므로 OutOfMemory 오류를 피하기 위해 동일한 논리를 사용하고 있습니다.
기본적으로 이 ImageDownloader 가 귀하의 답변입니다(대부분의 요구 사항을 다루기 때문에). 일부는 그 안에서 구현할 수도 있습니다.
이것은 많은 사람들이 여러 방법으로 해결한 Android의 일반적인 문제입니다. 내 생각에 내가 본 최고의 솔루션은 Picasso 라는 비교적 새로운 라이브러리입니다. 하이라이트는 다음과 같습니다.
Jake Wharton
이 주도합니다.ListView
감지나는 새로운 Android Volley 라이브러리 com.android.volley.toolbox.NetworkImageView
에서 NetworkImageView를 사용해 왔으며 꽤 잘 작동하는 것 같습니다. 분명히 이것은 Google Play 및 기타 새로운 Google 애플리케이션에서 사용되는 것과 동일한 보기입니다. 확실히 체크 아웃 할 가치가 있습니다.
글쎄, 인터넷에서 이미지 로딩 시간은 많은 솔루션이 있습니다. Android-Query 라이브러리를 사용할 수도 있습니다. 필요한 모든 활동을 제공합니다. 무엇을 하고 싶은지 확인하고 도서관 위키 페이지를 읽으십시오. 그리고 이미지 로딩 제한을 해결하세요.
이것은 내 코드입니다.
@Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.row, null); } ImageView imageview = (ImageView) v.findViewById(R.id.icon); AQuery aq = new AQuery(convertView); String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png"; aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() { @Override public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) { iv.setImageBitmap(bm); } )); return v; }
그것은 당신의 게으른 로딩 문제를 해결해야합니다.
이 문제는 Android 개발자들 사이에서 매우 인기가 있고 이 문제를 해결한다고 주장하는 라이브러리가 많이 있지만 그 중 일부만 표시되는 것 같습니다. AQuery 는 그러한 라이브러리 중 하나이지만 모든 측면에서 대부분의 라이브러리보다 우수하며 시도해 볼 가치가 있습니다.
이 Universal Loader가 가장 좋습니다. 지연 로딩에 대해 많은 RnD를 수행한 후 이것을 사용하고 있습니다.
특징
안드로이드 2.0 이상 지원
Shutterbug , Applidium의 가벼운 SDWebImage(iOS의 멋진 라이브러리) 포트를 Android로 살펴보십시오. 비동기 캐싱을 지원하고 실패한 URL을 저장하며 동시성을 잘 처리하고 유용한 하위 클래스가 포함되어 있습니다.
풀 리퀘스트(및 버그 리포트)도 환영합니다!
DroidParts 에는 시작하기 위해 구성이 필요 없는 ImageFetcher가 있습니다.
예를 들어 DroidPartsGram 복제:
Novoda에는 또한 훌륭한 지연 이미지 로딩 라이브러리가 있으며 Songkick, Podio, SecretDJ 및 ImageSearch와 같은 많은 앱이 해당 라이브러리를 사용합니다.
그들의 라이브러리는 여기 Github에서 호스팅되며 꽤 활동적인 이슈 트래커 도 있습니다. 이 답변을 작성하는 시점에 300개 이상의 커밋으로 그들의 프로젝트도 꽤 활동적인 것 같습니다.
지연 로딩 이미지에 어떤 라이브러리를 사용할지 결정하지 못하는 사람을 위한 간단한 팁:
네 가지 기본 방법이 있습니다.
DIY => 최고의 솔루션은 아니지만 몇 개의 이미지와 다른 라이브러리를 사용하는 번거로움 없이 가고 싶다면
Volley의 Lazy Loading 라이브러리 => Android의 사람들에게서. 그것은 훌륭하고 모든 것이지만 문서가 제대로 문서화되어 있지 않아 사용하기에 문제가 있습니다.
Picasso: 제대로 작동하는 간단한 솔루션으로 가져오려는 정확한 이미지 크기를 지정할 수도 있습니다. 사용하기는 매우 간단하지만 엄청난 양의 이미지를 처리해야 하는 앱의 경우 그다지 "성능"이 좋지 않을 수 있습니다.
UIL: 이미지를 지연 로드하는 가장 좋은 방법입니다. 이미지를 캐시하고(물론 권한이 필요함) 로더를 한 번 초기화한 다음 작업을 완료할 수 있습니다. 지금까지 본 것 중 가장 성숙한 비동기 이미지 로딩 라이브러리.
내 LazyList 포크를 확인하십시오. 기본적으로 ImageView 호출을 지연시켜 LazyList를 개선하고 두 가지 메서드를 만듭니다.
또한 이 객체에 싱글톤 을 구현하여 ImageLoader를 개선했습니다.
Facebook과 같은 Shimmer 레이아웃을 표시하려면 공식 Facebook 라이브러리가 있습니다. 페이스북 쉬머 안드로이드
그것은 모든 것을 처리합니다. 원하는 디자인 코드를 쉬머 프레임에 중첩 방식으로 넣으면됩니다. 다음은 샘플 코드입니다.
<com.facebook.shimmer.ShimmerFrameLayout android:id=“@+id/shimmer_view_container” android:layout_width=“wrap_content” android:layout_height="wrap_content" shimmer:duration="1000"> <here will be your content to display /> </com.facebook.shimmer.ShimmerFrameLayout>
그리고 여기에 대한 자바 코드가 있습니다.
ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container); shimmerContainer.startShimmerAnimation();
이 종속성을 gradle 파일에 추가하십시오.
implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'
위의 모든 코드에는 고유한 가치가 있지만 제 개인적인 경험으로 Picasso를 사용해 보십시오.
Picasso 는 이러한 목적을 위한 라이브러리이며 실제로 캐시 및 기타 모든 네트워크 작업을 자동으로 관리합니다. 프로젝트에 라이브러리를 추가하고 원격 URL에서 이미지를 로드하려면 한 줄의 코드만 작성해야 합니다.
여기를 방문하십시오: http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149
글라이드 라이브러리를 사용하십시오. 그것은 나를 위해 일했고 귀하의 코드에서도 작동합니다. gif뿐만 아니라 이미지에서도 작동합니다.
ImageView imageView = (ImageView) findViewById(R.id.test_image); GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView); Glide .with(this) .load(url) .listener(new RequestListener<String, GlideDrawable>() { @Override public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { return false; } }) .into(imagePreview); }
매력처럼 작동하는 다른 방법인 Android Query를 추천할 수 있습니다.
여기 에서 해당 JAR 파일을 다운로드할 수 있습니다.
AQuery androidAQuery = new AQuery(this);
예로서:
androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);
매우 빠르고 정확하며 이를 사용하면 로드 시 애니메이션, 비트맵 가져오기(필요한 경우) 등과 같은 더 많은 기능을 찾을 수 있습니다.
쿼리 를 사용해보십시오. 비동기식으로 이미지를 로드하고 캐시하는 놀랍도록 간단한 방법이 있습니다.
URLImageViewHelper 는 이를 도와주는 놀라운 라이브러리입니다.
public class ImageDownloader { Map<String, Bitmap> imageCache; public ImageDownloader() { imageCache = new HashMap<String, Bitmap>(); } // download function public void download(String url, ImageView imageView) { if (cancelPotentialDownload(url, imageView)) { // Caching code right here String filename = String.valueOf(url.hashCode()); File f = new File(getCacheDirectory(imageView.getContext()), filename); // Is the bitmap in our memory cache? Bitmap bitmap = null; bitmap = (Bitmap) imageCache.get(f.getPath()); if (bitmap == null) { bitmap = BitmapFactory.decodeFile(f.getPath()); if (bitmap != null) { imageCache.put(f.getPath(), bitmap); } } // No? download it if (bitmap == null) { try { BitmapDownloaderTask task = new BitmapDownloaderTask( imageView); DownloadedDrawable downloadedDrawable = new DownloadedDrawable( task); imageView.setImageDrawable(downloadedDrawable); task.execute(url); } catch (Exception e) { Log.e("Error==>", e.toString()); } } else { // Yes? set the image imageView.setImageBitmap(bitmap); } } } // cancel a download (internal only) private static boolean cancelPotentialDownload(String url, ImageView imageView) { BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); if (bitmapDownloaderTask != null) { String bitmapUrl = bitmapDownloaderTask.url; if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) { bitmapDownloaderTask.cancel(true); } else { // The same URL is already being downloaded. return false; } } return true; } // gets an existing download if one exists for the imageview private static BitmapDownloaderTask getBitmapDownloaderTask( ImageView imageView) { if (imageView != null) { Drawable drawable = imageView.getDrawable(); if (drawable instanceof DownloadedDrawable) { DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable; return downloadedDrawable.getBitmapDownloaderTask(); } } return null; } // our caching functions // Find the dir to save cached images private static File getCacheDirectory(Context context) { String sdState = android.os.Environment.getExternalStorageState(); File cacheDir; if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) { File sdDir = android.os.Environment.getExternalStorageDirectory(); // TODO : Change your diretcory here cacheDir = new File(sdDir, "data/ToDo/images"); } else cacheDir = context.getCacheDir(); if (!cacheDir.exists()) cacheDir.mkdirs(); return cacheDir; } private void writeFile(Bitmap bmp, File f) { FileOutputStream out = null; try { out = new FileOutputStream(f); bmp.compress(Bitmap.CompressFormat.PNG, 80, out); } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) out.close(); } catch (Exception ex) { } } } // download asynctask public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> { private String url; private final WeakReference<ImageView> imageViewReference; public BitmapDownloaderTask(ImageView imageView) { imageViewReference = new WeakReference<ImageView>(imageView); } @Override // Actual download method, run in the task thread protected Bitmap doInBackground(String... params) { // params comes from the execute() call: params[0] is the url. url = (String) params[0]; return downloadBitmap(params[0]); } @Override // Once the image is downloaded, associates it to the imageView protected void onPostExecute(Bitmap bitmap) { if (isCancelled()) { bitmap = null; } if (imageViewReference != null) { ImageView imageView = imageViewReference.get(); BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView); // Change bitmap only if this process is still associated with // it if (this == bitmapDownloaderTask) { imageView.setImageBitmap(bitmap); // cache the image String filename = String.valueOf(url.hashCode()); File f = new File( getCacheDirectory(imageView.getContext()), filename); imageCache.put(f.getPath(), bitmap); writeFile(bitmap, f); } } } } static class DownloadedDrawable extends ColorDrawable { private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference; public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) { super(Color.WHITE); bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>( bitmapDownloaderTask); } public BitmapDownloaderTask getBitmapDownloaderTask() { return bitmapDownloaderTaskReference.get(); } } // the actual download code static Bitmap downloadBitmap(String url) { HttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); HttpClient client = new DefaultHttpClient(params); final HttpGet getRequest = new HttpGet(url); try { HttpResponse response = client.execute(getRequest); final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url); return null; } final HttpEntity entity = response.getEntity(); if (entity != null) { InputStream inputStream = null; try { inputStream = entity.getContent(); final Bitmap bitmap = BitmapFactory .decodeStream(inputStream); return bitmap; } finally { if (inputStream != null) { inputStream.close(); } entity.consumeContent(); } } } catch (Exception e) { // Could provide a more explicit error message for IOException or // IllegalStateException getRequest.abort(); Log.w("ImageDownloader", "Error while retrieving bitmap from " + url + e.toString()); } finally { if (client != null) { // client.close(); } } return null; } }
이 문제가 있었고 lruCache를 구현했습니다. API 12 이상이 필요하거나 호환성 v4 라이브러리를 사용해야 한다고 생각합니다. lurCache는 빠른 메모리이지만 예산도 있기 때문에 diskcache를 사용할 수 있을지 걱정된다면... Caching Bitmaps 에 모두 설명되어 있습니다.
이제 다음과 같이 어디에서나 호출 하는 싱글톤인 구현을 제공하겠습니다.
//Where the first is a string and the other is a imageview to load. DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar);
다음은 웹 이미지를 검색할 때 어댑터의 getView에서 캐시하고 위의 코드를 호출하는 이상적인 코드입니다.
public class DownloadImageTask { private LruCache<String, Bitmap> mMemoryCache; /* Create a singleton class to call this from multiple classes */ private static DownloadImageTask instance = null; public static DownloadImageTask getInstance() { if (instance == null) { instance = new DownloadImageTask(); } return instance; } //Lock the constructor from public instances private DownloadImageTask() { // Get max available VM memory, exceeding this amount will throw an // OutOfMemory exception. Stored in kilobytes as LruCache takes an // int in its constructor. final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // Use 1/8th of the available memory for this memory cache. final int cacheSize = maxMemory / 8; mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in kilobytes rather than // number of items. return bitmap.getByteCount() / 1024; } }; } public void loadBitmap(String avatarURL, ImageView imageView) { final String imageKey = String.valueOf(avatarURL); final Bitmap bitmap = getBitmapFromMemCache(imageKey); if (bitmap != null) { imageView.setImageBitmap(bitmap); } else { imageView.setImageResource(R.drawable.ic_launcher); new DownloadImageTaskViaWeb(imageView).execute(avatarURL); } } private void addBitmapToMemoryCache(String key, Bitmap bitmap) { if (getBitmapFromMemCache(key) == null) { mMemoryCache.put(key, bitmap); } } private Bitmap getBitmapFromMemCache(String key) { return mMemoryCache.get(key); } /* A background process that opens a http stream and decodes a web image. */ class DownloadImageTaskViaWeb extends AsyncTask<String, Void, Bitmap> { ImageView bmImage; public DownloadImageTaskViaWeb(ImageView bmImage) { this.bmImage = bmImage; } protected Bitmap doInBackground(String... urls) { String urldisplay = urls[0]; Bitmap mIcon = null; try { InputStream in = new java.net.URL(urldisplay).openStream(); mIcon = BitmapFactory.decodeStream(in); } catch (Exception e) { Log.e("Error", e.getMessage()); e.printStackTrace(); } addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon); return mIcon; } /* After decoding we update the view on the main UI. */ protected void onPostExecute(Bitmap result) { bmImage.setImageBitmap(result); } } }
출처 : http:www.stackoverflow.com/questions/541966/how-to-lazy-load-images-in-listview-in-android
Makefile에서 .PHONY의 목적은 무엇입니까? (0) | 2021.12.20 |
---|---|
java.net.URLConnection을 사용하여 HTTP 요청을 실행하고 처리하는 방법 (0) | 2021.12.20 |
Linux에서 실행되는 C++ 코드를 프로파일링하려면 어떻게 해야 합니까? (0) | 2021.12.08 |
커밋을 푸시하기 위해 https 자격 증명을 캐시하는 방법이 있습니까? (0) | 2021.12.08 |
SQL Server 테이블에 열이 있는지 확인하는 방법은 무엇입니까? (0) | 2021.12.08 |