2011-11-17 4 views
1

ImageView 및 TextView가 포함 된 ListView가 있습니다. 나는 서브 클래 싱 된 AsyncTask를 통해 인터넷에서 이미지를로드 할 수 있도록 ArrayAdapter를 서브 클래 싱합니다. 지금까지 좋은 모든 것.convertView 사용할 때의 문제, 내가하지 않을 때의 문제

문제는 convertView를 사용하려고하면 이미지가 잘못된 행으로 잠깐 재활용되는 문제가 있다는 것입니다. (이것은 회사의 로고이므로 좋지 않습니다.)

그러나 convertView를 사용하지 않으면 사용자가 스크롤 할 때 이미지가 손실됩니다. 그래서 아래로 스크롤하면 이미지가 인터넷에서 다시로드됩니다 (데이터 사용, 배터리 수명 등).

이 문제를 해결할 수있는 간단한 방법이 있습니까? 매번 인터넷에서로드하거나 이미지를 옮길 수 있습니까?

는 여기에 지금까지 사용하고있는 작업은 다음과 같습니다

public class SupplierAdapter extends ArrayAdapter<Supplier>{ 
    int resource; 
    String response; 
    Context context; 

    public SupplierAdapter(Context context, int resource, List<Supplier> suppliers) { 
     super(context, resource, suppliers); 
     this.resource = resource; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent){ 
    LinearLayout view; 
     Supplier s = getItem(position); 

     if(convertView == null){ 
      view = new LinearLayout(getContext()); 
      String inflater = Context.LAYOUT_INFLATER_SERVICE; 
      LayoutInflater vi; 
      vi = (LayoutInflater) getContext().getSystemService(inflater); 
      vi.inflate(resource, view, true); 
     } else { 
      view = (LinearLayout) convertView; 
     } 

     ImageView iv = (ImageView) view.findViewById(R.id.thumbnail); 
     // s.getThumbnail returns a URL 
     new DownloadImageTask(iv).execute(s.getThumbnail()); 

     TextView titleText =(TextView) view.findViewById(R.id.titleText); 
     titleText.setText(s.getTitle()); 
     titleText.setTag(s.getId()); 

     return view; 
    } 
} 

모든 대단히 감사합니다 :)

+0

SimpleAdapter를 사용하고 캐싱을 고려 ​​했습니까? –

+0

@ 단, 그렇지 않았습니다. 정확히 캐시해라. SD 카드에 저장 하시겠습니까? 그게 어떻게 작동하는지 모르겠습니다. –

+0

SimpleAdapter는 String 배열을 처리하는 것 이상의 기능을하는 경우에 더 좋습니다. 캐싱의 경우 SD에 저장하고 업데이트를 확인할 수있는 기준을 마련하십시오. –

답변

2

존, raptureinvenice.com 님의 WebImageView을 사용해보세요. 최근에이 쉽고 가벼운 라이브러리를 사용하기 위해 코드를 리팩토링했으며 지금까지는 그렇게 훌륭했습니다. 그것은 쉽게 2 레벨 캐시를 제공하고 동시에 여러 대상을 업데이트하며 설정하기가 매우 쉽습니다. 이미지를 표시하는 데 약 1/20의 요청이 줄어들 것 같습니다. 라이브러리의 잘못이 될 수있는 숨어있는 버그 이외에는 훌륭합니다.

+0

니스, 이건 현저하게 나와있는 것과 비슷하지만, 제 고용주를 위해 작성한 것처럼 제 코드를 공유하지 못했습니다. Funnily I * think *는 구현시에도 비슷한 버그가있는 것 같습니다. 메모리 사용량과 관련 있다고 생각합니다. 내 유일한 자격은 SoftReferences를 사용한다는 점입니다. SoftReferences는 Android에서 다소 손상되었습니다. 필자는 LruCache 대신에 일관된 최대 캐시 크기를 제공하기 위해 선호하는 LruCache를 사용합니다. – kabuko

+0

감사합니다. 이상적이었습니다! –

1

이 제품은 성가 시게 복잡한 문제입니다 도움이됩니다. 두 번째 스레드 (AsyncTask 귀하의 경우)에서 더 똑똑한 업데이트 상단의 성능을 원활하게하기 위해 캐시 (메모리 및 디스크 캐시)의 두 계층을 가지고있었습니다. 동일한 이미지를 두 번 다운로드하지 않는 것과 같은 작은 세부 정보가 많이 있습니다 (여러 목록 항목에 동일한 회사 로고가있는 경우 문제가됩니다). 보여지는 잘못된 이미지의 주된 문제점은 ImageView와 관련된 현재 URL을 추적하고, 최종 이미지를 설정하기 전에 AsyncTask에 전달 된 것과 동일한 지 확인함으로써 간단히 해결할 수 있습니다. 어쩌면 그 정보를 HashMap에 저장할 수 있습니다. 저는 사실이 모든 것들을 WebImageView 클래스로 추상화하여 ImageView를 확장하여 모든 재사용이 가능하도록했습니다.

1

RAM 이미지 캐싱의 경우 SoftReference을 사용할 수 있습니다.

ImageView iv = (ImageView) view.findViewById(R.id.thumbnail); 
// s.getDrawable returns a SoftReference to Drawable 
SoftReference<Drawable> thumbRef = s.getDrawable(); 
Drawable thumb = thumbRef.get(); 
if (thumb == null) { 
    new DownloadImageTask(s).execute(); 
} else { 
    iv.setDrawable(thumb); 
} 

DownloadImageTaskSoftReference로 포장, 이미지를 얻을 컬렉션에 대한 참조를 설정하고 기저의 데이터가 변경 어댑터 통지합니다 : 그래서 코드는 다음과 같이 될 것이다. 근원의, 디자인은 능률적 일 수 있었다, 그러나 이것은 다만 거친 계획이다.

+0

이것은 꽤 유망 해 보입니다. 나는 그것을 한 발 줘서 내가 어떻게 시작하는지 알려줄 것입니다. 고마워요. –

1

당신은 몇 가지 이미지를 다운로드하고 당신이 큰 이미지를 표시 할 필요가없는 경우, 다음과 같은 코드를 사용할 수 있습니다 필요한 경우. 비트 맵을 메모리에 저장합니다. 이미지가 너무 크지 않다는 것이 효과적입니다.

나는 상황에 내 코드를 변경 :

수입 android.graphics.Bitmap;

공용 클래스 공급 {

// Data 
private String mText; 
private Bitmap mImage; 
private String mImageUrl; 

// Flags 
private boolean mIsLoading; 

public Supplier() { 
    mText  = "test"; 
    mImage  = null; 
    mImageUrl = "image_url"; 
    mIsLoading = false; 
} 

public Supplier setLoadingStatus(boolean pIsLoading){ 
    mIsLoading = pIsLoading; 
    return this; 
} 

public boolean isLoading(){ 
    return mIsLoading; 
} 

public Supplier setImageUrl(String pImageUrl){ 
    mImageUrl = pImageUrl; 
    return this; 
} 

public String getImageUrl(){ 
    return mImageUrl; 
} 

public Supplier setText(String pText){ 
    mText = pText; 
    return this; 
} 

public String getText(){ 
    return mText; 
} 

public Supplier setImageBitmap(Bitmap bmp){ 
    mImage = bmp; 
    return this; 
} 

public Bitmap getImageBitmap(){ 
    return mImage; 
}  

}

수입 때 java.io.IOException; 가져 오기 java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; 가져 오기 java.util.ArrayList;

import android.R; import android.content.Context; android.graphics.Bitmap; android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; 가져 오기 android.view.LayoutInflater; import android.view.View; 가져 오기 android.view.ViewGroup; 가져 오기 android.widget.BaseAdapter; 가져 오기 android.widget.ImageView; 가져 오기 android.widget.TextView;

공용 클래스 TestAdapter는 BaseAdapter {

protected static final int MSG_IMAGE_DOWNLOADED = 0; 

// Constants 
private final String TAG = "TestAdapter"; 

private ArrayList<Supplier> mItems; 
private Context mContext; 
private LayoutInflater mLf; 
private Handler mHandler; 


public TestAdapter(Context pContex) { 
    mContext = pContex; 
    mLf   = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mItems  = new ArrayList<Supplier>(); 
    mHandler = new Handler(){ 
     public void handleMessage(Message msg) { 
      switch (msg.what) { 
      case MSG_IMAGE_DOWNLOADED: 
       if(null != msg.obj){ 
        mItems.get(msg.arg1).setImageBitmap((Bitmap)msg.obj) 
             .setLoadingStatus(false); 
        notifyDataSetChanged(); 
       } 
       break; 

      default: 
       break; 
      } 
     }; 
    }; 
} 

public TestAdapter addItem(Supplier pItem){ 
    mItems.add(pItem); 
    return this; 
} 

@Override 
public int getCount() { 
    return mItems.size(); 
} 

@Override 
public Supplier getItem(int position) { 
    return mItems.get(position); 
} 

@Override 
public long getItemId(int position) { 
    return position; 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder vh; 

    if(null == convertView){ 
     convertView  = mLf.inflate(R.layout.your_resource, parent, false); 
     vh    = new ViewHolder(); 
     vh.mTextView = (TextView)convertView.findViewById(R.id.your_textview_from_resource); 
     vh.mImage  = (ImageView)convertView.findViewById(R.id.yout_imageview_from_resource); 
     convertView.setTag(vh); 
    }else{ 
     vh = (ViewHolder)convertView.getTag(); 
    }  

    vh.mTextView.setText(mItems.get(position).getText()); 
    if(mItems.get(position).getImageBitmap() == null && !mItems.get(position).isLoading()){ 
     // download image 
     downloadImage(mItems.get(position).getImageUrl(), position); 
     // set a flag to know that the image is downloading and it is not need to 
     // start another download if the getView method is called again. 
     mItems.get(position).setLoadingStatus(true); 
    }else{ 
     vh.mImage.setImageBitmap(mItems.get(position).getImageBitmap()); 
    } 
    return null; 
} 

private void downloadImage(String pImageUrl, int pItemPosition){ 
    final int cItemPosition = pItemPosition; 
    final String cImageUrl = pImageUrl; 

    Thread tGetImage = new Thread(new Runnable() {   
     @Override 
     public void run() {    
      Message msg = new Message(); 
      msg.what = MSG_IMAGE_DOWNLOADED; 

      BitmapFactory.Options options = new BitmapFactory.Options();                        
      Bitmap bmImg;  
      URL  myFileUrl = null; 

      try { 
       myFileUrl= new URL(cImageUrl); 
      } catch (MalformedURLException e) { 
       e.printStackTrace();       
      }      
      try { 
       HttpURLConnection conn= (HttpURLConnection)myFileUrl.openConnection(); 
       conn.setDoInput(true); 
       conn.connect(); 
       InputStream is = conn.getInputStream(); 
       bmImg   = BitmapFactory.decodeStream(is, null, options); 

       is.close(); 
       conn.disconnect();   
       msg.obj  = bmImg;      
      } catch (IOException e) { 
       e.printStackTrace();       
      }      
      msg.arg1 = cItemPosition; 
      mHandler.sendMessage(msg);    
     } 
    }); 
    tGetImage.start(); 
} 

private class ViewHolder{ 
    public TextView  mTextView; 
    public ImageView mImage; 
} 

}

코드는 테스트하지 않고 작동합니다을 확장합니다.

관련 문제