2011-04-22 2 views
5

Gallery 위젯과 함께 사용할 지연 로딩 어댑터를 만들고 싶습니다.지연된 이미지 로딩 어댑터가있는 android 갤러리보기 "stutters"

즉, getView()은 즉시 ImageView을 반환하고 나중에 다른 메커니즘은 setImageBitmap() 메서드를 비동기 적으로 호출합니다. 나는 ImageView을 확장하는 "게으른"ImageView을 만들어이 작업을 수행했습니다.

public class GalleryImageView extends ImageView { 

    // ... other stuff here ... 

    public void setImage(final Looper looper, final int position) { 

    final Uri uri = looper.get(position); 
    final String path = looper.sharePath(position); 

    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      GalleryBitmap gbmp = new GalleryBitmap(context, uri, path); 
      final Bitmap bmp = gbmp.getBitmap(); // all the work is here 
      handler.post(new Runnable() { 

       @Override 
       public void run() { 
        if (GalleryImageView.this.getTag().equals(uri)) { 
         setImageBitmap(bmp); 
        } 
       } 
      }); 
     } 
    }).start(); 
} 

} 

나는 Gallery 천천히 스크롤

은 중심 이미지는 센터로 터지는 유지합니다. 설명하기는 어렵지만, 실제로는 성가시다. 나는 또한 회 전자 어댑터에 대해 동일한 접근법을 시도했으며 완벽하게 작동합니다.

아이디어가 있으십니까?

+0

나는 같은 문제가있다. 스크롤링은 끈적 거리고 모든 것이 스와질랜드의 위치를 ​​정하기 전에 좌, 우로 퍼지게됩니다. 혹시 해결책을 찾았습니까? –

+0

사용중인 Android 버전은 무엇입니까? 그리고 사용자 정의 ImageView를 사용하지 않을 때이 문제가 발생합니까? 모든 이미지를로드 한 후에 문제가 중지됩니까? –

+0

당신은'갤러리' –

답변

12

해결 방법은 미리보기 이미지를 가져올 때 더 지능적인 방법을 구현하는 것입니다. 사용자가 목록을 비웃는 동안 미리보기 이미지를 가져 오는 것이 무의미합니다. 기본적으로 Romain Guy의 Shelves 응용 프로그램에서 구현 된 것과 같은 것을 원합니다. 그것은 당신의 getView에서 메모리 캐시에 존재하는 경우

  • 만 이미지를 설정합니다

    는 다음은 메모리 캐시의 일부 양식을 구현하는 데 필요한 대부분의 반응 갤러리를 얻을 수 및 수행 . 이미지가 설정되었는지 또는 다운로드가 필요한지 여부를 나타내는 플래그를 설정합니다. 당신은 또한 SD 카드와 내부 메모리의 캐시에 메모리를 유지할 수 있습니다. 플링이 현재 진행중이 아니라면, 그냥 스크롤 할 때 볼 수있는 저해상도 (inSampleSize 또는 16 또는 8로 설정) 버전을 보여줍니다. res 버전은 사용자가 이미지를 보냈을 때 자동으로로드됩니다.
  • 추가 OnItemSelectedListener (및 초기화 할 때 setCallbackDuringFling(false)를 호출해야합니다) 사용자의 손가락이 (당신의 범위를 찾기 위해 getFirstVisiblePositiongetLastVisiblePosition를 사용할 수있는 최대 인 경우에만 다운로드 을 필요로하는 모든 표시되는 항목에 대한 새로운 썸네일을 다운로드하는 보기가 표시됨)
  • 또한 사용자가 손가락을 떼면 1을 봅니다. 사용자가 손가락을 아래로 내린 이후 선택한 위치가 변경된 경우 2. 그렇다면 OnItemSelectedListener로 인해 다운로드가 시작되었는지 여부 - 그렇지 않은 경우 그런 다음 하나를 시작하십시오. 이것은 플링이 발생하지 않는 경우를 잡으므로 OnItemSelected은이 상황에서 항상 손가락으로 불려지기 때문에 아무 것도하지 않습니다. 핸들러를 사용하여 갤러리의 애니메이션 시간만큼 다운로드 시작을 지연시킬 수 있습니다. onItemSelected이 호출되거나 ACTION_DOWN 이벤트가 발생할 때마다 처리기에 게시 된 모든 지연된 메시지를 지우십시오.
  • 이미지를 다운로드 한 후 해당 이미지를 요청한보기가 있는지 확인한 다음 해당보기를 업데이트하십시오.

기본 갤러리 구성 요소가보기 재활용을 제대로 구현하지 못합니다. 또한 어댑터의 각 위치가 고유 한보기를 갖고 있다고 가정합니다. 이러한 항목을 재활용 할 때 화면이 무의미 해집니다.) 편집 : 더보기에 그것은 무의미하지 않습니다. - 그러나 용어로는 리사이클 러가 아닙니다 다음/이전보기 중 하나를 선택하는 대신 레이아웃 변경 중에 현재보기에 getView을 호출하지 않아도됩니다.그 몇 가지 힌트 Does a replacement for Gallery with View recycling exist?에 대한 내 대답을 참조 -

이것은 당신이 (비싼) 전망을 많이 팽창 할 것입니다 의미, 당신의 getView 메서드에 전달 된 convertView 매개 변수가 더 자주 그 null이 될 수 없습니다 것을 의미합니다. (추신 : 이후 그 코드를 수정했습니다 - 레이아웃 단계 장소에서 레이아웃 단계와 스크롤 단계에 다른 휴지통을 사용하고 레이아웃 휴지통의보기를 해당 위치에 따라 검색하고 getView를 호출하지 마십시오. 빈에서 얻은 뷰는 정확히 동일한 뷰일 것이므로 null이 아니며 레이아웃 단계가 끝나면 레이아웃 휴지통을 지우십시오 - 이것은 좀 더 깔끔하게 만듭니다.

추신 : 또한 매우주의해야합니다. OnItemSelected에서 무엇을할까요? 즉 위에서 언급 한 장소에 있지 않은 한 가능한 적은 노력을하십시오. 예를 들어 내 갤러리 위의 TextView에있는 텍스트를 OnItemSelected으로 설정했습니다. 이 전화를 미리보기 이미지를 업데이트 한 위치와 동일한 지점으로 이동하면 눈에 띄는 차이가 있습니다.

+0

아, 감사합니다. 이것은 내가 합리적인 방향으로 나아갈 것 같이 보인다. 이 시점에서 나는 작업 항목을 펀트하고 고정 된 수의 정적 이미지로 이동하여 함께 스크롤 할 수 있습니다. 적어도이 버전의 경우. :) –

+0

그래서 사용자가 갤러리에서 무언가를 선택할 때까지 이미지가로드되지 않습니까? 사용자가 볼 수없는 경우 선택하려는 항목을 사용자가 어떻게 알 수 있습니까? 나는 뭔가를 놓치고 있어야합니다. fling 동작이 멈출 때 항목을 선택하지 않을 때 다운로드 /로드 이미지 작업을 시작하려는 것 같습니다. 갤러리에서 스크롤이 완료되면 어떻게 알 수 있습니까? 갤러리 앱이 취하는 접근법은 처음에는 더 빠른 샘플 이미지를로드 한 다음 나중에 전체 버전을로드하는 것입니다. 문제가 네트워크 다운로드 인 경우이 작동하지 않습니다. –

+0

이 경우 이미지가 다운로드 될 때까지 로딩 스피너를 표시하십시오. 또한 갤러리는 보이지 않는 뷰를 생성하기 때문에'onItemSelected'에서 미리보기 이미지를 다운로드하면 몇 개의 뷰에 대한 이미지가 왼쪽과 오른쪽으로 다운로드됩니다. 갤러리가 스크롤을 마쳤을 때 (OnItemSelected 리스너가 호출되고 손가락이 아래쪽에 있지 않은 경우) 알려면 리스너가 항목이 가운데로 이동할 때마다 호출됩니다. –

2

이것은 Gallery의 onLayout 메소드의 버그 일 수 있습니다. 가능한 해결 방법은 http://code.google.com/p/android/issues/detail?id=16171을 확인하십시오.

+0

의 주된 문제가 무엇인지 자세히 설명해 주실 수 있습니까?이 문제는이 해결책이 효과가 있다고 생각하지 않습니다. 스크롤하는 동안 (그리고 250ms 이후) 모든 레이아웃 요청을 멈추지 만 fling 중에는 레이아웃 요청을 멈추지 않습니다 (갤러리 용 onFling 참조).지금까지 내가 볼 수있는 방법은 갤러리에있는 모든 관련 메소드와 필드가 비공개로되어있어 별똥별을 다 끝냈다는 것을 알 수 없기 때문에 가능한 한 최선이라고 생각합니다 (이 페이지에서 내 답변을 따로 떼어 놓으십시오) 이 방법으로 전달 된 속도의 일부 기능에서 작동하지만 FlingRunnable 및 Scroller 클래스를 보면 이는 간단하지 않습니다. – Dori

12

답변을 드리겠습니다. setImage... 방법 중 하나는 내부에 배치 패스 ImageView에라고

예를 들어, 위와 같이 setImageBitmap()을 갖는다

public void setImageDrawable(Drawable drawable) { 
    if (mDrawable != drawable) { 
     mResource = 0; 
     mUri = null; 
     updateDrawable(drawable); 
     requestLayout(); //layout requested here! 
     invalidate(); 
    } 
} 

호출 등

public void setImageBitmap(Bitmap bm) { 
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm)); 
} 

로 정의되며, 요구되는 현재 갤러리의 중심에 가장 가까운 이미지의 중심에 갤러리 '스냅하는'효과.

내가 이것을 방지하기 위해 수행 한 작업은 갤러리에로드되는보기 thats에 명시적인 높이와 너비 (dip 초)가 있고 레이아웃 요청을 무시하는 ImageView 하위 클래스를 사용하는 것입니다. 이 갤러리는 여전히 레이아웃 패스가 있지만 갤러리의 이미지가 변경 될 때마다이 작업을 수행하지 않아도됩니다. 갤러리보기의 너비와 높이가 WRAP_CONTENT으로 설정된 경우에만 필요하다고 생각합니다. . invalidate()이 여전히 setImageDrawable()에서 호출되므로 설정시 이미지가 그려집니다.

내 매우 간단 ImageView 하위 클래스!

/** 
* This class is useful when loading images (say via a url or file cache) into 
* ImageView that are contained in dynamic views (Gallerys and ListViews for 
* example) The width and height should be set explicitly instead of using 
* wrap_content as any wrapping of content will not be triggered by the image 
* drawable or bitmap being set (which is normal behaviour for an ImageView) 
* 
*/ 
public class ImageViewNoLayoutRefresh extends ImageView 
{ 
    public ImageViewNoLayoutRefresh(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
    } 

    public ImageViewNoLayoutRefresh(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
    } 

    public ImageViewNoLayoutRefresh(Context context) 
    { 
     super(context); 
    } 

    @Override 
    public void requestLayout() 
    { 
     // do nothing - for this to work well this image view should have its dims 
     // set explicitly 
    } 
} 

편집 : 나는 onItemSelected 방법도 작동 할 수 있음을 언급해야한다,하지만 난 그에 훅 필요에 따라 일어나고 마리 동안 나는 좀 더 유연한 접근 방식이 생각하는 위를 내놓았다

+1

멋진. drawable을 설정할 때 requestLayout()을 호출하지 않는 자체 ImageView를 구현하려고 시도했지만 requestLayout을 무시하고 아무 작업도 수행 할 수 없습니다. 타이 남자 – weakwire

+1

위대한 대답, 고마워. – Ljdawson

+0

그 때문에 많은 시간을 절약 할 수있었습니다. 고마워. –