Android의 ListView에서 이미지를 지연로드하는 방법


1930

를 사용하여 ListView해당 이미지와 관련된 일부 이미지 및 캡션을 표시하고 있습니다. 인터넷에서 이미지를 가져옵니다. 텍스트가 표시되는 동안 UI가 차단되지 않고 이미지가 다운로드 될 때 이미지가 표시되도록 이미지를 지연로드하는 방법이 있습니까?

총 이미지 수는 고정되어 있지 않습니다.


10
GreenDroid의 AsyncImageView를 사용할 수 있습니다 . 전화 setUrl하세요.
Pascal Dimassimo

7
나는 그것을 사용했다. 훌륭한 구현입니다. AsyncImageView는 대규모 GreenDroid 프로젝트의 일부이므로 AsyncImageView 만 있으면 응용 프로그램을 더 크게 만들 수 있습니다. 또한
GreenDroid

5
내 의견으로는 이미지의 비동기 로딩에 가장 적합한 Android-http-image-manager 이 라이브러리를 사용해 볼 수도 있습니다.
Ritesh Kumar Dubey

34
피카소를 사용하면 모든 것이 자동으로 수행됩니다. 'Picasso.with (yourContext) .load (img src / path / drawable here) .into (imageView 즉 대상);' 그게 다야!
Anuj Sharma

6
사용해보십시오 : github.com/nostra13/Android-Universal-Image-Loader는 ,이 라이브러리는 매우 빠르고 게으른 로딩 및 이미지 캐싱을위한 효율적이다
krunal 파텔

답변:


1086

내 앱이 현재 표시하고있는 이미지를 담기 위해 만든 내용은 다음과 같습니다. 여기서 사용중인 "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();
    }
}

104
프로그램에서 OutOfMemoryException이 발생하지 않도록 SoftReferences를 사용해야한다고 생각합니다. 힙 크기가 증가 할 때 GC가 소프트 레퍼런스를 지울 수 있기 때문에 몇 초 후에 이미지를 해당 목록에 넣을 수 있고로드하기 전에 이미지가 존재하는지 확인한 후 다시 다운로드하지 않는지 확인하십시오. 목록에서 그것을 다시 softref 목록에 다시 넣고 언젠가 후에 당신의 hardlist를 제거 할 수 있습니다 :)
AZ_

36
Google Shelves 프로젝트는 code.google.com/p/shelves
AZ_

12
페치 스레드를 시작하지 않고 drawableMap에 이미지가 포함되어있을 때 반환을 놓치지 마십시오?
Karussell

5
이 코드에는 몇 가지 문제가 있습니다. 첫째로 당신은 드로어 블 캐시해야하는 메모리 누수가 발생합니다 stackoverflow.com/questions/7648740/...를 . 둘째, 캐시 자체는 지워지지 않으므로 영원히 커질 것입니다. 이는 또 다른 메모리 누수입니다.
satur9nine

10
되지 않은 하나에 대해 들어 본 적이 LRU Cache developer.android.com/training/displaying-bitmaps/...
무하마드 바바

1024

이미지 가있는 게으른 목록 (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로 이미지를 디코딩하여 메모리 소비를 줄입니다. 또한 재활용 뷰를 올바르게 처리하려고합니다.

대체 텍스트


7
감사합니다. 거의 모든 프로젝트 내 코드의 약간 수정 된 버전을 사용하고 있습니다 : code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/…
shaman.sir

3
누구나 Gilles Debunne의 코드를 대안으로 보았습니다. 내가 볼 수있는 두 가지 큰 차이점은 1) 메모리 캐싱 대 SD 카드 및 2) 스레드 풀 대신 AsyncTasks 사용입니다. android-developers.blogspot.com/2010/07/…
Richard

4
버그가 있으며 때때로 발생합니다. : java.lang.ArrayIndexOutOfBoundsException : 배열 색인이 범위를 벗어남 : 0 10-13 09 : 58 : 46.768 : ERROR / AndroidRuntime (24250) : at java.util.Vector.elementAt (Vector.java:331) 10-13 09 : 58 : 46.768 : ERROR / AndroidRuntime (24250) : at java.util.Vector.get (Vector.java:445) 10-13 09 : 58 : 46.768 : ERROR / AndroidRuntime (24250) : com.my.app.image에서 .ImageLoader $ PhotosQueue.Clean (ImageLoader.java:91)
Mikooos

64
이 코드를 자신의 프로젝트에 추가하려면 매니페스트에 외부 캐시 권한을 추가해야한다는 저와 같은 초보자를 위해 추가하고 싶습니다. 감사합니다
Adam

2
@BruceHill 최신 소스 코드에는 photosQueue가 없습니다. 아주 오래된 버전을 사용하고있는 것 같습니다.
Fedor

551

오픈 소스 기기 Universal Image Loader를 권장 합니다. 원래 Fedor Vlasov의 프로젝트 LazyList를 기반으로하며 그 이후로 크게 개선되었습니다.

  • 멀티 스레드 이미지 로딩
  • 와이드 튜닝 ImageLoader 구성 가능 (스레드 실행기, 다운 레이더, 디코더, 메모리 및 디스크 캐시, 디스플레이 이미지 옵션 등)
  • 메모리 및 / 또는 장치의 파일 시스템 (또는 SD 카드)에서 이미지 캐싱 가능
  • 로딩 프로세스 "듣기"가능성
  • 별도의 옵션으로 모든 디스플레이 이미지 호출을 사용자 정의 할 수 있음
  • 위젯 지원
  • 안드로이드 2.0 이상 지원


16
제작자가 자신의 소중한 아기 (일회성 해결책이 아님)로 취급하고 유지하는 훌륭한 "이미지 로딩"코드를 찾고 있다면, 방금 찾은 것입니다. Big
Ups

정말 대단한 일이지만 내 목록보기가 약간 뒤떨어집니다. 최고의 성능을 나타내는 'ImageLoader'빌드 ... 또는 'DisplayImageOptions'때문일 수 있습니다.
dinigo

이 gridview를 너무 좋아하지만 튜토리얼에는 사용할 수 없습니다. 나는 안드로이드 초보자입니다. gridview에 대한 응용 프로그램을 만들지 만 응용 프로그램은 targetSdkVersion 15이므로 백그라운드 스레드의 프로세스에 Asynctask를 사용해야합니다. 이 gridview를 사용했지만 작동하지 않습니다. targetSdkVersion 15에서 어떻게 사용할 수 있습니까?
kongkea

당신은 태그 별도의 질문을 만들 수 있습니다 [보편적 인 이미지 로더를]
nostra13

3
공식 안드로이드 문서를 읽고 직접이 작업을 시도한 후에, 나는이 라이브러리가 모두 이미지 로딩의 끝이라고 확신합니다. 공감할 수 없습니다.
Core

158

성능을위한 멀티 스레딩Gilles Debunne의 튜토리얼, .

이것은 Android 개발자 블로그에서 가져온 것입니다. 제안 된 코드는 다음을 사용합니다.

  • AsyncTasks.
  • 단단하고 제한된 크기 FIFO cache .
  • 부드럽고 쉽게 garbage collect 캐시입니다.
  • 자리 Drawable 당신은 다운로드하는 동안.

여기에 이미지 설명을 입력하십시오


10
2.1에서도 잘 작동합니다. AndroidHttpClient를 사용하지 마십시오.
Thomas Ahle

2
@ thomas-ahle 감사합니다. 2.2에서 구현되었으므로 AndroidHttpClient가 2.1에서 오류를 발생시키는 것을 보았지만 실제로 대체 할 다른 것을 찾지는 못했습니다.
Adinia

4
@ 아디나 당신이 옳아 요, 잊어 버렸습니다. 그러나 레시피에는 일반적인 HttpClient로 수행 할 수없는 것은 없습니다.
Thomas Ahle

여러 곳에서 안드로이드 커널이 이전 버전의 시스템에 비해 이러한 레퍼런스를 수집하기를 열망하기 때문에 구글은 소프트 레퍼런스를 권장하지 않는다고 들었다.
Muhammad Ahmed AbuTalib가

108

업데이트 :이 답변은 현재 매우 효과적이지 않습니다. 가비지 콜렉터는 SoftReference 및 WeakReference에 대해 적극적으로 작동하므로이 코드는 새 앱에는 적합하지 않습니다. (대신 Universal Image Loader 와 같은 라이브러리를 사용해보십시오. 다른 답변에서 제안 된 .)

코드에 대해서는 James, SoftReference 사용에 대한 제안은 Bao-Long에게 감사드립니다. James 코드에서 SoftReference 변경 사항을 구현했습니다. 불행히도 SoftReferences로 인해 이미지가 너무 빨리 가비지 수집되었습니다. 필자의 경우 목록 크기가 제한되어 있고 이미지가 작기 때문에 SoftReference 항목이 없으면 문제가 없습니다.

1 년 전에 Google 그룹에 대한 SoftReferences에 대한 토론이 있습니다 : 링크 링크 . 너무 이른 가비지 수집에 대한 해결책으로 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();
}

3
하드 세대 및 소프트 세대와 같은 세대를 만들 수 있습니다. 당신은 3 초 안에 액세스되지 않은 모든 이미지를 지우고 캐시 지우기 시간을 수정할 수 있습니다. 당신은 구글 선반 프로젝트를 볼 수 있습니다
AZ_

developer.android.com/reference/java/lang/ref/… SoftReference 문서에는 캐싱에 대한 참고 사항이 있습니다. "캐싱에 대한 소프트 참조는 피하십시오"섹션을 참조하십시오. 대부분의 응용 프로그램은 소프트 참조 대신 android.util.LruCache를 사용해야합니다.
vokilam

코드에 감탄했지만 이제 새로운 Android O / S에는 '공격적인'가비지 수집이 있습니다. 약한 참고 문헌을 보유하는 것은 나에게 의미가 없습니다.
j2emanue

@ j2emanue 대답의 맨 위에 표시하려고했을 때 SoftReferences가 너무 빨리 가비지 수집됩니다. 더 명확하게하기 위해이 답변을 편집하려고합니다.
TalkLittle

96

피카소

Jake Wharton의 Picasso Library를 사용하십시오. (ActionBarSherlock 개발자의 완벽한 이미지 로딩 라이브러리)

Android 용 강력한 이미지 다운로드 및 캐싱 라이브러리.

이미지는 Android 애플리케이션에 필요한 컨텍스트와 시각적 감각을 추가합니다. Picasso는 응용 프로그램에서 번거롭지 않은 이미지 로딩을 허용합니다. 종종 한 줄의 코드로도 가능합니다!

Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

피카소는 안드로이드에서 이미지 로딩의 많은 함정을 자동으로 처리합니다.

어댑터에서 ImageView 재활용 및 다운로드 취소 처리 최소한의 메모리 사용으로 복잡한 이미지 변환. 자동 메모리 및 디스크 캐싱.

피카소 제이크 와튼의 도서관

활주

글라이드는 미디어 디코딩, 메모리 및 디스크 캐싱 및 리소스 풀링을 간단하고 사용하기 쉬운 인터페이스로 감싸는 Android 용 빠르고 효율적인 오픈 소스 미디어 관리 프레임 워크입니다.

Glide는 비디오 스틸, 이미지 및 애니메이션 GIF 가져 오기, 디코딩 및 표시를 지원합니다. Glide에는 개발자가 거의 모든 네트워크 스택에 플러그인 할 수있는 유연한 API가 포함되어 있습니다. 기본적으로 Glide는 커스텀 HttpUrlConnection 기반 스택을 사용하지만 대신 Google의 Volley 프로젝트 또는 Square의 OkHttp 라이브러리에 플러그인하는 유틸리티 라이브러리도 포함합니다.

Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);

글라이드의 주요 초점은 모든 종류의 이미지 목록을 가능한 한 매끄럽고 빠르게 스크롤하는 것입니다. 그러나 글라이드는 원격 이미지를 가져 와서 크기를 조정하고 표시해야하는 거의 모든 경우에 효과적입니다.

글라이드 이미지 로딩 라이브러리

페이스 북에 의해 프레스코

Fresco는 Android 애플리케이션에서 이미지를 표시하기위한 강력한 시스템입니다.

Fresco는 이미지 로딩 및 디스플레이를 관리하므로 사용자는 필요하지 않습니다. 네트워크, 로컬 스토리지 또는 로컬 리소스에서 이미지를로드하고 이미지가 도착할 때까지 자리 표시자를 표시합니다. 캐시에는 두 가지 레벨이 있습니다. 하나는 메모리에 있고 다른 하나는 내부 저장소에 있습니다.

프레스코 깃 허브

Android 4.x 이하에서는 Fresco가 Android 메모리의 특수 영역에 이미지를 넣습니다. 이를 통해 응용 프로그램을 더 빠르게 실행할 수 있습니다.

프레스코 문서


피카소 광장에서 개발 한 라이브러리입니다
LordRaydenMK

82

고성능 로더-여기에 제안 된 방법을 검토 한 후 Ben의 솔루션 을 약간 변경하여 사용했습니다.

  1. 비트 맵을 사용하는 것보다 드로어 블을 사용하는 것이 더 빠르다는 것을 깨달았습니다.

  2. SoftReference를 사용하는 것은 좋지만 캐시 된 이미지가 너무 자주 삭제되므로 이미지 참조가 포함 된 링크 된 목록을 추가하여 미리 정의 된 크기에 도달 할 때까지 이미지가 삭제되지 않도록합니다.

  3. 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;
}
}

잘 작동합니다! BTW 클래스 이름에 오타가 있습니다.
멀린

5
다른 사람에게 시간을 절약 할 수있는 경우 : 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;
Michael Reed

대단히 감사합니다. 이것은 훌륭한 구현입니다. 또한 드로어 블이로드 될 때 다른 자리 표시자를 배치하여 사용자가 피드백을 얻을 수 있습니다.
Juan Hernandez

또한 기본 FIFO 대신 executorService (mThreadPool)에서 LIFO 대기열을 사용하는 것이 더 좋으므로 요청 된 마지막 이미지 (보이는 이미지)가 먼저로드됩니다. stackoverflow.com/questions/4620061/how-to-create-lifo-executor
Juan Hernandez

9
@MichaelReed, Eclipse 사용자 인 경우 Ctrl-Shift-O (숫자 0이 아닌 문자 O)를 사용하는 것이 좋습니다. 가져 오기 추가 프로세스를 자동화하고 가져옵니다. Mac을 사용하는 경우 Command-Shift-O를 대신 사용하십시오.
SilithCrowe

78

나는이 안드로이드 교육을 따랐으며 메인 UI를 차단하지 않고 이미지를 다운로드하는 데 훌륭한 역할을한다고 생각합니다. 또한 많은 이미지를 통한 캐싱 및 스크롤 처리를 처리합니다. 효율적으로 큰 비트 맵로드


죄송합니다. Google IO 앱의 단일 클래스 만 가리 켰습니다 (편집하기에 너무 늦었습니다). 캐시 클래스와 동일한 패키지 에서 찾을 수있는 모든 이미지로드 및 캐싱 유틸리티 클래스를 실제로 연구해야합니다 .
mkuech

누구나 목록보기를위한 이미지로드 / 캐싱을 처리하는 데 도움이되도록 iosched 앱의 util 폴더에서 DiskLruCache, Image * .java 파일을 가져 오는 것이 좋습니다? 주제에 대한 온라인 개발자 안내서를 따르는 것이 가치가 있지만이 클래스 (iosched의 클래스)는 패턴에 따라 조금 더 나아갑니다.
Gautam

65

1. Picasso 는 응용 프로그램에서 번거롭지 않은 이미지 로딩을 허용합니다. 종종 한 줄의 코드로도 가능합니다!

Gradle 사용 :

implementation 'com.squareup.picasso:picasso:2.71828'

한 줄의 코드 만!

Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

2. 글라이드 부드러운 스크롤링에 중점을 둔 Android 용 이미지 로딩 및 캐싱 라이브러리

Gradle 사용 :

repositories {
  mavenCentral() 
  google()
}

dependencies {
   implementation 'com.github.bumptech.glide:glide:4.7.1'
   annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
}

// 간단한보기 :

  Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

3. 프레스코 는 안드로이드 응용 프로그램에서 이미지를 표시하는 강력한 시스템입니다.

Fresco 시작하기


- :이 튜토리얼 PICASOO을 위해 더 도움이 될 수 androidtutorialshub.com/... 및 글라이드 : - androidtutorialshub.com/...
파크 하얏트 vasan

52

목록보기에서 이미지의 지연 로딩을 수행하는 방법을 설명하는 자습서를 작성했습니다. 재활용 및 동시성 문제에 대해 자세히 설명합니다. 또한 많은 스레드 생성을 방지하기 위해 고정 스레드 풀을 사용합니다.

Listview Tutorial에서 이미지의 지연 로딩


41

내가하는 방법은 스레드를 시작하여 백그라운드에서 이미지를 다운로드하고 각 목록 항목에 대한 콜백을 전달하는 것입니다. 이미지 다운로드가 완료되면 콜백을 호출하여 목록 항목의보기를 업데이트합니다.

그러나이 방법은 뷰를 재활용 할 때 제대로 작동하지 않습니다.


각 이미지에 스레드를 사용하는 것도 내가 사용하는 접근법입니다. 모델을 뷰와 분리하면 모델을 액티비티 외부 (예 : '애플리케이션'클래스와 같은) 외부에 유지하여 캐시 된 상태로 유지할 수 있습니다. 이미지가 많은 경우 리소스가 부족하지 않도록주의하십시오.
제임스 A 윌슨

정교하게 부탁드립니다. 나는 안드로이드 개발에 익숙하지 않다. 그래도 팁 주셔서 감사합니다
lostInTransit

14
각 이미지에 대해 새 스레드를 시작하는 것은 효과적인 해결책이 아닙니다. 메모리와 동결 UI에 많은 스레드가 생길 수 있습니다.
Fedor

Fedor는 동의했다. 나는 보통 큐와 스레드 풀을 사용한다. 이것이 가장 좋은 방법이다.
jasonhudgins


29

이것은 많은 사람들이 여러 가지 방법으로 해결 한 Android의 일반적인 문제입니다. 내 생각에 가장 좋은 해결책은 Picasso 라는 비교적 새로운 라이브러리 입니다. 주요 내용은 다음과 같습니다.

  • 오픈 소스는하지만,로 향했다 Jake WhartonActionBarSherlock의 명성.
  • 한 줄의 코드로 네트워크 또는 앱 리소스에서 이미지를 비동기 적으로로드
  • 자동 ListView감지
  • 자동 디스크 및 메모리 캐싱
  • 커스텀 변형 가능
  • 구성 가능한 많은 옵션
  • 매우 간단한 API
  • 자주 업데이트

29

새로운 Android Volley Library에서 NetworkImageView를 사용 com.android.volley.toolbox.NetworkImageView하고 있으며 꽤 잘 작동하는 것 같습니다. 분명히 이것은 Google Play 및 기타 새로운 Google 응용 프로그램 에서 사용되는 것과 동일한 견해입니다 . 체크 아웃 가치가 있습니다.


1
나는이 최선의 해결책이라고 생각 - 다른 답변은 매우 오래된 - 헤딩슛은 빠르고 정말하고 제이크 warthons 솔루션 PERFEKT 그것을 disklrucache와 함께 - 내가 다른 사람을 많이 시도하지만 하나가 안정적이고 빠른 발리로
알렉산더 Sidikov Pfeif

26

인터넷에서 이미지 로딩 시간에는 많은 솔루션이 있습니다. 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;
}

지연 로딩 문제를 해결해야합니다.


좋은 일이지만 프로젝트에 포함 할 Jar 파일이 필요합니다. 여기에서 해당 JAR 파일을 다운로드 할 수 있습니다. AQuery androidAQuery = new AQuery (this); 링크 : code.google.com/archive/p/android-query/downloads
셀림 라자

25

나는이 문제가 안드로이드 개발자들 사이에서 매우 인기가 있다고 생각 하며이 문제를 해결한다고 주장하는 라이브러리가 많이 있지만 그중 소수만이 마크에있는 것 같습니다. AQuery 는 그러한 라이브러리 중 하나이지만 모든 측면에서 대부분의 라이브러리보다 낫고 시도해 볼 가치가 있습니다.


22

이 범용 로더를 사용하는 것이 가장 좋습니다. 지연 로딩에 많은 RnD를 수행 한 후 이것을 사용하고 있습니다.

범용 이미지 로더

풍모

  • 멀티 스레드 이미지 로딩 (비동기 또는 동기화)
  • ImageLoader 구성의 광범위한 사용자 정의 (스레드 실행기, 다운로더, 디코더, 메모리 및 디스크 캐시, 디스플레이 이미지 옵션 등)
  • 모든 디스플레이 이미지 호출에 대한 많은 사용자 정의 옵션 (스텁 이미지, 캐싱 스위치, 디코딩 옵션, 비트 맵 처리 및 표시 등)
  • 메모리 및 / 또는 디스크 (장치의 파일 시스템 또는 SD 카드)의 이미지 캐싱
  • 청취 로딩 프로세스 (다운로드 진행률 포함)

안드로이드 2.0 이상 지원

여기에 이미지 설명을 입력하십시오


20

Applidium의 경량 SDWebImage (iOS의 멋진 라이브러리) 포트 인 Android에 대한 Shutterbug를 살펴보십시오 . 비동기 캐싱을 지원하고, 실패한 URL을 저장하고, 동시성을 잘 처리하며, 유용한 서브 클래스가 포함됩니다.

풀 요청 (및 버그 보고서)도 환영합니다!


16

DroidParts 에는 ImageFetcher 가 있으며이를 시작하기 위해 구성이 필요 없습니다.

  • 최근에 사용한 디스크 및 메모리 내 최소 사용 LRU (Least Recent Used) 캐시를 합니다.
  • 이미지를 효율적으로 디코딩합니다.
  • 백그라운드 스레드에서 비트 맵 수정을 지원합니다.
  • 간단한 크로스 페이드 기능이 있습니다.
  • 이미지 로딩 진행 콜백이 있습니다.

예를 들어 DroidPartsGram 을 복제 하십시오 .

여기에 이미지 설명을 입력하십시오


안녕하세요, 코드 예제를 살펴 보았지만 ArrayAdapter와 함께 ImageFetcher를 사용하는 데 문제가 있습니다. 제 질문을 보시겠습니까? stackoverflow.com/questions/21089147/… 감사합니다 =]
masha

16

지연 로딩 이미지에 어떤 라이브러리를 사용해야하는지 잘 모르는 사람을위한 간단한 팁 :

네 가지 기본 방법이 있습니다.

  1. DIY => 가장 좋은 해결책은 아니지만 몇 가지 이미지와 다른 라이브러리를 사용하는 번거 로움없이 가고 싶다면

  2. 발리의 게으른 로딩 라이브러리 => 안드로이드의 사람들로부터. 그것은 훌륭하고 모든 것이지만 문서화가 잘되어 있지 않아서 사용하는 데 문제가 있습니다.

  3. 피카소 : 작동하는 간단한 솔루션으로, 가져 오려는 정확한 이미지 크기를 지정할 수도 있습니다. 사용하기 매우 간단하지만 엄청난 양의 이미지를 처리해야하는 앱의 경우 "성능"이 아닐 수도 있습니다.

  4. UIL : 이미지를 지연로드하는 가장 좋은 방법입니다. 이미지를 캐시하고 (물론 권한이 필요함) 로더를 한 번 초기화 한 다음 작업을 수행 할 수 있습니다. 내가 지금까지 본 가장 성숙한 비동기 이미지 로딩 라이브러리.


15

Novoda는 또한 게으른 이미지 로딩 라이브러리를 가지고 있습니다. 있으며 Songkick, Podio, SecretDJ 및 ImageSearch와 같은 많은 앱이 라이브러리를 사용합니다.

그들의 라이브러리는 여기 Github에서 호스팅 되며 꽤 활발한 이슈 트래커 도 있습니다. 이 답변을 작성할 당시 300 개 이상의 커밋으로 프로젝트가 활발한 것으로 보입니다.


1
실제로 Novoda는 훌륭한 라이브러리이지만 때로는 거대한 라이브러리가 필요하지 않고 솔루션에 대한 간단한 접근 방식이 필요합니다. 그렇기 때문에 Github의 LazyList가 너무 좋습니다. 앱이 listView에 이미지 만 표시하고 앱의 주요 기능이 아닌 경우 다른 활동을 사용하여 더 가벼운 것을 선호합니다. 그렇지 않으면 자주 사용해야하고 핵심의 일부라는 것을 알고 있다면 Novoda를 사용해보십시오.
Nicolas Jafelle

13

LazyList의 포크를 확인하십시오 . 기본적으로 ImageView 호출을 지연시켜 LazyList를 개선하고 두 가지 방법을 만듭니다.

  1. "이미지로드 중 ..."과 같은 것을 넣어야 할 때
  2. 다운로드 한 이미지를 표시해야 할 때

또한 이 객체에 싱글 톤 을 구현하여 ImageLoader를 개선했습니다 .


12

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'

그 모습은 다음과 같습니다.쉬머 안드로이드


11

위의 코드는 모두 가치가 있지만 개인적인 경험으로 피카소를 사용해보십시오.

피카소 는 캐시와 다른 모든 네트워크 작업을 자동으로 관리하는이 목적을 위해 특별히 라이브러리입니다. 프로젝트에 라이브러리를 추가하고 원격 URL에서 이미지를로드하기 위해 한 줄의 코드 만 작성하면됩니다.

여기를 방문하십시오 : http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149


9

글라이드 라이브러리를 사용하십시오. 그것은 나를 위해 일했고 코드에서도 작동합니다. 이미지뿐만 아니라 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);
}

7

매력처럼 작동하는 다른 방법 인 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);

매우 빠르고 정확하며,이를 사용하면로드 할 때 애니메이션, 비트 맵 (필요한 경우) 가져 오기 등과 같은 더 많은 기능을 찾을 수 있습니다.


7

부여 Aquery을 시도합니다. 이미지를 비동기식으로로드하고 캐시하는 놀랍도록 간단한 방법이 있습니다.



4
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;
 }
}

4

나는이 문제가 있었고 lruCache를 구현했다. API 12 이상이 필요하거나 호환성 v4 라이브러리를 사용한다고 생각합니다. lurCache는 빠른 메모리이지만 예산도 있으므로 디스크 캐시를 사용할 수 있다고 걱정되면 캐싱 비트 맵에 설명되어 있습니다.

이제 다음과 같이 어디에서나 호출 하는 싱글 톤 인 구현을 제공 할 것입니다 .

//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);
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.