2012-11-15 4 views
1

가능한 중복 : 나는 이미지를 표시 목록보기를 사용하고
Android Out of Memory error with Lazy Load images
Outofmemory error during scrolling the listview fastlylistview 스크롤하는 동안 outofmemory 오류를 해결하는 방법?

는 페이스 북 api.I의 이름은 수의 이미지를 표시 할 수 correctly.My 문제는 때입니다 목록을 빨리 스크롤합니다.

11-15 18:41:29.841: E/dalvikvm-heap(32303): 786432-byte external allocation too large for this process. 
11-15 18:41:29.887: I/dalvikvm-heap(32303): Clamp target GC heap from 32.095MB to 32.000MB 
11-15 18:41:29.887: E/GraphicsJNI(32303): VM won't let us allocate 786432 bytes 
11-15 18:41:29.887: D/dalvikvm(32303): GC_FOR_MALLOC freed 0K, 51% free 4380K/8903K, external 23826K/25864K, paused 31ms 
11-15 18:41:29.887: D/skia(32303): --- decoder->decode returned false 
11-15 18:41:29.887: W/dalvikvm(32303): threadid=18: thread exiting with uncaught exception (group=0x40018560) 
11-15 18:41:29.887: E/AndroidRuntime(32303): FATAL EXCEPTION: Thread-29 
11-15 18:41:29.887: E/AndroidRuntime(32303): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
11-15 18:41:29.887: E/AndroidRuntime(32303): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
11-15 18:41:29.887: E/AndroidRuntime(32303): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470) 
11-15 18:41:29.887: E/AndroidRuntime(32303): at com.beerbro.utils.ImageLoader.decodeFile(ImageLoader.java:156) 
11-15 18:41:29.887: E/AndroidRuntime(32303): at com.beerbro.utils.ImageLoader.getBitmap(ImageLoader.java:99) 
11-15 18:41:29.887: E/AndroidRuntime(32303): at com.beerbro.utils.ImageLoader$PhotosLoader.run(ImageLoader.java:214) 

그러나 내가 이 목록보기를 천천히 스크롤하면 오류가 발생하지 않습니다.

내 어댑터 클래스에서 Imageloader 클래스 displayImage 메서드를 호출하여 URL을 비트 맵으로 변환하고 이미지 뷰로 설정합니다. 여기

public class MySimpleArrayAdapter extends ArrayAdapter<String> { 
    private Activity context; 
    ArrayList<String> namear,msgar,idar,profimage,postimage,commentsnum,objectid,urlString; 

    ImageLoader imageLoader; 
    Bitmap[] bitdata; 


    public MySimpleArrayAdapter(Activity c,int i,ArrayList<String> postpic, ArrayList<String> names,ArrayList<String> msg,ArrayList<String> id,ArrayList<String> proimg,Bitmap[] bit,ArrayList<String> comment,ArrayList<String> objid,ArrayList<String> web) { 

     super(c, i, names); 
    Log.e("adapter","adap"); 
    this.context = c; 
    this.namear = names; 
    this.msgar = msg; 
    this.idar = id; 
    this.profimage=proimg; 
    this.postimage=postpic; 
    this.bitdata=bit; 
    this.commentsnum=comment; 
    this.objectid=objid; 
    this.urlString=web; 
    this.imageLoader = new ImageLoader(context); 
    } 


    @Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     View rowView=convertView ; 
     LayoutInflater inflator = getLayoutInflater(); 
     rowView = inflator.inflate(R.layout.walldata, null); 

     TextView name1 = (TextView) rowView.findViewById(R.id.name); 
     TextView message1 = (TextView) rowView.findViewById(R.id.msg); 
     ImageView profimg= (ImageView) rowView.findViewById(R.id.profile_pic); 
     ImageView postimg= (ImageView) rowView.findViewById(R.id.picpost); 
    TextView comments = (TextView) rowView.findViewById(R.id.comment); 

    Log.e("user",idar.get(position)); 


    Log.e("adapter","adap"); 
    name1.setText(namear.get(position)); 
    if(msgar.get(position)!=""){ 
    message1.setText(msgar.get(position)); 

    } 
    else 
    { 
     message1.setVisibility(View.GONE); 
    } 
    if(!postimage.get(position).equals("")) 
    {try{ 
     imageLoader.DisplayImage(postimage.get(position).replace(" ", "%20"), postimg) ; 

    } 
    catch(Exception e){ 
     e.printStackTrace(); 
    } 
    } 
    else 
    { 
     postimg.setVisibility(View.GONE); 
    } 
    try{ 
     imageLoader.DisplayImage(profimage.get(position).replace(" ", "%20"), profimg) ; 

    } 
    catch(Exception e){ 
     e.printStackTrace(); 
    } 

     comments.setText(commentsnum.get(position)+"\t"+"Comments"); 
     comments.setOnClickListener(new OnClickListener() { 


     public void onClick(View v) { 
      Intent myintent=new Intent(Wall.this,Comments.class); 
      myintent.putExtra("name", namear.get(position)); 
      myintent.putExtra("profimg", profimage.get(position)); 
      myintent.putExtra("message", msgar.get(position)); 
      myintent.putExtra("postpic", postimage.get(position)); 
      myintent.putExtra("objectid", objectid.get(position)); 
      myintent.putExtra("commentsnum",commentsnum.get(position)); 
      myintent.putExtra("webservice", urlString.get(position)); 
      startActivity(myintent); 

     } 
    }); 

    return rowView; 
    } 

나의하여 ImageLoader 클래스

public class ImageLoader { 

    MemoryCache memoryCache=new MemoryCache(); 
    FileCache fileCache; 
    private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); 

    public ImageLoader(Context context){ 

     photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1); 

     fileCache=new FileCache(context); 
    } 

    public void DisplayImage(String url,ImageView imageView) 
    { 
     imageViews.put(imageView, url); 


     Bitmap bitmap=memoryCache.get(url); 

     if(bitmap!=null) 
     { 
      imageView.setBackgroundDrawable(new BitmapDrawable(bitmap)); 

      System.gc(); 
     } 
     else 
     { 
      queuePhoto(url, imageView); 

     }  
    } 

    private Bitmap createScaledBitmap(Bitmap bitmap, int i, int j, int k) { 
     return null; 
    } 

    private void queuePhoto(String url, ImageView imageView) 
    { 
     //This ImageView may be used for other images before. So there may be some old tasks in the queue. We need to discard them. 
     photosQueue.Clean(imageView); 
     PhotoToLoad p=new PhotoToLoad(url, imageView); 
     synchronized(photosQueue.photosToLoad){ 
      photosQueue.photosToLoad.push(p); 
      photosQueue.photosToLoad.notifyAll(); 
     } 

     //start thread if it's not started yet 
     if(photoLoaderThread.getState()==Thread.State.NEW) 
      photoLoaderThread.start(); 
    } 

    public Bitmap getBitmap(String url) 
    { 
     File f=fileCache.getFile(url); 

     //from SD cache 
     Bitmap b = decodeFile(f); 
     if(b!=null) 
      return b; 

     //from web 
     try { 
      Bitmap bitmap=null; 
      URL imageUrl = new URL(url); 
      HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); 
      conn.setConnectTimeout(30000); 
      conn.setReadTimeout(30000); 
      InputStream is=conn.getInputStream(); 
      OutputStream os = new FileOutputStream(f); 
      Utils.CopyStream(is, os); 
      os.close(); 
      bitmap = decodeFile(f); 
      return bitmap; 
     } catch (Exception ex){ 
      ex.printStackTrace(); 
      return null; 
     } 
    }//Lalit 

    //decodes image and scales it to reduce memory consumption 
    private Bitmap decodeFile(File f){ 
     try { 
      //decode image size 
      BitmapFactory.Options o = new BitmapFactory.Options(); 
      o.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(f),null,o); 


      //Find the correct scale value. It should be the power of 2. 

      final int REQUIRED_SIZE=Wall.width; 
      final int REQUIRED_SIZE1=Wall.height; 

      int width_tmp=o.outWidth, height_tmp=o.outHeight; 
      int scale=1; 

      while(true){ 
       if((width_tmp/2<REQUIRED_SIZE)&&(height_tmp/2<REQUIRED_SIZE1)) 
        break; 
       width_tmp/=2; 
       height_tmp/=2; 
       scale*=2; 
      } 

      //decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inJustDecodeBounds = true; 
      BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 
      o2.inSampleSize=scale; 
      o2.inJustDecodeBounds = false; 

      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 


     } catch (FileNotFoundException e) {} 
     return null; 
    } 

    //Task for the queue 
    private class PhotoToLoad 
    { 
     public String url; 
     public ImageView imageView; 
     public PhotoToLoad(String u, ImageView i){ 
      url=u; 
      imageView=i; 
     } 
    } 

    PhotosQueue photosQueue=new PhotosQueue(); 

    public void stopThread() 
    { 
     photoLoaderThread.interrupt(); 
    } 

    //stores list of photos to download 
    class PhotosQueue 
    { 
     private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>(); 

     //removes all instances of this ImageView 
     public void Clean(ImageView image) 
     { 
      for(int j=0 ;j<photosToLoad.size();){ 
       if(photosToLoad.get(j).imageView==image) 
        photosToLoad.remove(j); 
       else 
        ++j; 
      } 
     } 
    } 

    class PhotosLoader extends Thread { 
     public void run() { 
      try { 
       while(true) 
       { 
        //thread waits until there are any images to load in the queue 
        if(photosQueue.photosToLoad.size()==0) 
         synchronized(photosQueue.photosToLoad){ 
          photosQueue.photosToLoad.wait(); 
         } 
        if(photosQueue.photosToLoad.size()!=0) 
        { 
         PhotoToLoad photoToLoad; 
         synchronized(photosQueue.photosToLoad){ 
          photoToLoad=photosQueue.photosToLoad.pop(); 
         } 
         Bitmap bmp=getBitmap(photoToLoad.url); 
         memoryCache.put(photoToLoad.url, bmp); 
         String tag=imageViews.get(photoToLoad.imageView); 
         if(tag!=null && tag.equals(photoToLoad.url)){ 
          BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView); 
          Activity a=(Activity)photoToLoad.imageView.getContext(); 
          a.runOnUiThread(bd); 
         } 
        } 
        if(Thread.interrupted()) 
         break; 
       } 
      } catch (InterruptedException e) { 
       //allow thread to exit 
      } 
     } 
    } 

    PhotosLoader photoLoaderThread=new PhotosLoader(); 

    //Used to display bitmap in the UI thread 
    class BitmapDisplayer implements Runnable 
    { 
     Bitmap bitmap; 
     ImageView imageView; 
     public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;} 
     public void run() 
     { 
      if(bitmap!=null) 
       imageView.setBackgroundDrawable(new BitmapDrawable(bitmap)); 

     } 
    } 

    public void clearCache() { 
     memoryCache.clear(); 
     fileCache.clear(); 
    } 
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels,int width,int height) { 

     Bitmap output = Bitmap.createBitmap(width,height, Config.ARGB_8888); 
     Canvas canvas = new Canvas(output); 

     final int color = 0xff424242; 
     final Paint paint = new Paint(); 
     final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 
     final RectF rectF = new RectF(rect); 
     final float roundPx = pixels; 

     paint.setAntiAlias(true); 
     canvas.drawARGB(0, 0, 0, 0); 
     paint.setColor(color); 
     canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 

     paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
     canvas.drawBitmap(bitmap, rect, rect, paint); 

     return output; 
    } 

내 장치의 화면 크기 즉, 480 * 854 개까지 이미지를 확장하고, 당신이하여 ImageLoader 클래스에서이 문제를 찾을 수 있습니다, 또한 쉽게 이해

여기 언급
 final int REQUIRED_SIZE=Wall.width; 
      final int REQUIRED_SIZE1=Wall.height; 

      int width_tmp=o.outWidth, height_tmp=o.outHeight; 
      int scale=1; 

      while(true){ 
       if((width_tmp/2<REQUIRED_SIZE)&&(height_tmp/2<REQUIRED_SIZE1)) 
        break; 
       width_tmp/=2; 
       height_tmp/=2; 
       scale*=2; 
      } 
    } 

메모리가 비트 맵을로드하기에 충분하지 않다는 것을 알게되면 런타임시 메모리를 어떻게 할당 해제 할 수 있는지 알 수 없습니다. 제발 stackoverflow 및 다른 링크를 참조 할 수 있지만 couldnt이이 문제를 해결할 수 있습니다.

+1

을 네 번째로 동일한 질문을 던졌고 이번에는 다른 결과가 나올 것으로 예상하십니까? http://www.brainyquote.com/quotes/quotes/a/alberteins133991.html 질문에 대한 좋은 답변을 얻지 못하면 마지막으로 좋은 조언을 받았습니다. 그것을 읽으십시오. – Simon

+0

코드를 제공하는데 더 많은 노력을 기울이십시오. –

+0

안녕하세요. hannes. 최대한의 코드를 제공했습니다. 이해가 안되면 나에게 묻습니다. 지금이 문제에 대해 상담하십시오. – veerendra

답변

1

글쎄, 내가 생각할 수있는 한 가지 방법은 onScrollListener을 사용하고 리스너가 설정할 수있는 어댑터에 플래그를 추가하는 것입니다.

목록이 스크롤 될 때 (flag = true) 어댑터가 이미지로드를 건너 뛰도록하십시오. 목록 스크롤이 중지되면 (flag = false) 어댑터가 이미지를로드하게하십시오. 어댑터에서 notifyDataSetChanged()을 호출하여 이미지로드를 트리거합니다.

listView.setOnScrollListener(new OnScrollListener() { 
    public void onScroll(AbsListView view, int firstVisible, 
    int visibleCount, int total) { 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
      if (scrollState != 0) 
       listView.getAdapter()).isScrolling = true; 
      else { 
       listView.getAdapter().isScrolling = false; 
       listView.getAdapter().notifyDataSetChanged(); 
      } 
     } 
    }); 

을 그리고 어댑터 단순히이 사용하여 이미지를로드하는 코드를 둘러싸고 : 우리는 어댑터 isScrolling에서 플래그를 호출하면

, 리스너는 다음과 같을 수 그래서,

if (!isScrolling) { 
    // code to load images 
} 
+0

위와 같이 배치하려고하면 여러 마커 오류가 발생합니다. – veerendra

+0

listView.getAdapter()에서 isScrolling이 없습니다. isScrolling ... –

+0

어댑터를 확장하고 추가 할 때가 있습니다 ... – Barak

0

내가 꽤 확실하지 오전하지만 problems.first과 이미지 구성 요소를이

BitmapDrawable bd = (BitmapDrawable) imgView.getDrawable(); 
      if (bd != null) 
      { 
       bd.getBitmap().recycle(); 
       imgView.setImageBitmap(null); 
      } 
+0

if (bitmap! = null) 뒤에 bitmap.recycle()을 추가했습니다. { imageView.setBackgroundDrawable (새 BitmapDrawable (비트 맵)); System.gc(); bitmap.recycle(); // bitmap = null; // imageView.setImageBitmap (getRoundedCornerBitmap (bitmap, 10,70,70))); // imageView.setImageBitmap (비트 맵); // Log.v ("first", "first"); } – veerendra

+0

그것은 u는 문제 – veerendra

+0

헬로 흐드을했다 didnt한다; ImageView postimg = (ImageView) rowView.findViewById (R.id.picpost); 해당 행 추가 후 BitmapDrawable bd = (BitmapDrawable) profimg.getDrawable(); if (bd! = null) { bd.getBitmap(). 재활용(); profimg.setImageBitmap (null); } bd = (BitmapDrawable) postimg.getDrawable(); if (bd! = null) { bd.getBitmap(). 재활용(); postimg.setImageBitmap (null); } – veerendra

1

어쩌면 두 가지 원인을 초기화 한 후 다음 줄을 추가, 당신은 생성되었던 목록보기 항목의 istance을 다시 해달라고. 나는 당신의 코드를 보았는데 왜 당신은 그 코드를 주목 하는가? 너무 빨리 목록보기를 스크롤하면 VM이 즉각적으로 빠르기 때문에 메모리가 부족해 지므로 버퍼를 사용하는 것이 좋습니다. 둘째, 비트 맵이 너무 커서 스크롤이 너무 빠르면 VMM이 압력을받습니다. 이러한 문제를 해결하기 위해 비트 맵의 ​​크기를 줄일 수 있습니다. 내 답장이 당신을 위해 뭔가를 할 수 있기를 바랍니다.

+0

if (convertview == null) {여기에 모든 인스턴스 가져 오기}를 유지하여 재사용하려고했지만 선행로드 된 이미지를 먼저 표시하고 실제 이미지를로드하는 데 시간이 걸립니다. 그리고 영원한 스크롤의 경우 이미지는 변경하고 시간을 멈추었을 때 이미지 – veerendra

+0

을 두 번째로 설정해야합니다. 비트 맵이 너무 크면 처리해야합니다. 비트 맵 작게 만들기 – honeypig

관련 문제