2012-05-07 5 views
0

내 응용 프로그램에 따르면 먼저 내 리소스의 모든 이미지를 내부 메모리로 복사 한 다음 Image Slide에서 왼쪽 또는 오른쪽으로 인덱스의 메모리에서 이미지를 가져 와서 보여줍니다. . 그리고 저는 AsynTask로이 작업을하고 있습니다. 약 10 개의 이미지가 표시되면 응용 프로그램이 검은 색 화면으로 바뀌고 로그 고양이가 "이 프로세스에 너무 큰 외부 할당"이라고 표시됩니다. 여기에서 읽은 것들에 따르면 문제는 AsyncTask에 관한 것이라고 생각합니다.이 작업에 사용 된 메모리를 해제 할 수 없습니다. 나는 이미지를 갤러리로 보여주는 데 사용되는 세 가지 다른 액티비티를 가지고 있으며, 각각의 액티비티는 asyncTask를 사용하여 이미지를 보여줍니다.안드로이드에서 AsyncTask 및 메모리 부족 문제가 발생했습니다.

아래 코드 중 일부는 도움이 될 것입니다. 미리 감사드립니다. 여기 내 이미지는 슬라이딩 이미지에 따라 이미지 다운로더를 실행하는 데 사용됩니다.

lid1 = new LocalImageDownloader(imageSwitcher, myContext, path, nameList.get(curIndex)); 
      lid1.execute(); 

      imageSwitcher.setOnTouchListener(new OnTouchListener() { 
       public boolean onTouch(View v, MotionEvent event) { 

        if (event.getAction() == MotionEvent.ACTION_DOWN) { 
         downX = (int) event.getX(); 
         Log.i("event.getX()", " downX " + downX); 
         return true; 
        } 

        else if (event.getAction() == MotionEvent.ACTION_UP) { 
         upX = (int) event.getX(); 
         Log.i("event.getX()", " upX " + downX); 
         if (upX - downX > 100) { 

          //curIndex current image index in array viewed by user 
          curIndex--; 
          if (curIndex < 0) { 
           curIndex = imageList.size()-1; 
          } 

          imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(Activities.this,R.anim.slide_in_left)); 
          imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(Activities.this,R.anim.slide_out_right)); 

          lid1.cancel(true); 
          lid1 = new LocalImageDownloader(imageSwitcher, myContext, path, nameList.get(curIndex)); 
          lid1.execute(); 
         } 

         else if (downX - upX > -100) { 

          curIndex++; 
          if (curIndex == imageList.size()) { 
           curIndex = 0; 
          } 

          imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(Activities.this,R.anim.slide_in_right)); 
          imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(Activities.this,R.anim.slide_out_left)); 

          lid1.cancel(true); 
          lid1 = new LocalImageDownloader(imageSwitcher, myContext, path, nameList.get(curIndex)); 
          lid1.execute(); 
         } 
         return true; 
        } 
        return false; 
       } 
      }); 

이 내부 메모리에서 이미지를 얻을 내 AsyncTask를하고,

public class LocalImageDownloader extends AsyncTask<String, Void, Bitmap> { 

String url; 
Drawable d; 
Context myContext; 

String path; 
String fileName; 

ProgressDialog dialog; 
int REQUIRED_SIZE=600; 

private final WeakReference<ImageSwitcher> imageViewReference; 

public LocalImageDownloader(ImageSwitcher imageSwitcher,Context myContext, String path, String fileName) { 
    this.myContext = myContext; 
    this.path = path; 
    this.fileName = fileName; 
    imageViewReference = new WeakReference<ImageSwitcher>(imageSwitcher); 
} 

@Override 
protected Bitmap doInBackground(String... urls) { 
    publishProgress(); 
    return null; 
} 

@Override 
protected void onPreExecute() { 
    dialog = ProgressDialog.show(myContext, "", "Loading Images...", true); 
    super.onPreExecute(); 
} 

@Override 
protected void onPostExecute(Bitmap result) { 

    try { 
     if (imageViewReference != null) { 
      ImageSwitcher imageSwitcher = imageViewReference.get(); 
      if (imageSwitcher != null) { 
       imageSwitcher.setImageDrawable(getLocalImage()); 
      } 
     } 
    } catch (FileNotFoundException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    dialog.dismiss(); 
} 

public Drawable getLocalImage() throws IOException { 

    File file = new File(path,fileName); 

    //Decode image size 
    BitmapFactory.Options o = new BitmapFactory.Options(); 
    o.inJustDecodeBounds = true; 
    BitmapFactory.decodeStream(new FileInputStream(file),null,o); 

    //The new size we want to scale to 

    //Find the correct scale value. It should be the power of 2. 
    int scale=1; 
    while(o.outWidth/scale/2>=this.REQUIRED_SIZE && o.outHeight/scale/2>=this.REQUIRED_SIZE) 
     scale*=2; 

    //Decode with inSampleSize 
    BitmapFactory.Options o2 = new BitmapFactory.Options(); 
    o2.inSampleSize=scale; 
    o.inJustDecodeBounds = false; 

    return new BitmapDrawable(BitmapFactory.decodeStream(new FileInputStream(file), null, o2)); 
} 

} 

편집 : 나는 더 효율적으로 비트 맵을 사용하는 몇 가지 방법을 적용하고 지금은 그들을 밀어있어 메모리에 있지만 거의 동일한 오류가 있습니다. 이미지 중 일부가 메모리에 저장되고 이미지의 일부가 검은 색 화면으로 표시되고 같은 오류가 발생합니다. "외부 할당이 너무 많습니다." 어떤 생각을하는 방법?

아래 메모리 캐시 코드는 다음과 같습니다. MemoryCache 개체를 매개 변수로 AsyncTask에 보냅니다.

public class MemoryCache { 

private static final String TAG = "MemoryCache"; 
private Map<String, Bitmap> cache=Collections.synchronizedMap(
     new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering 
private long size=0;//current allocated size 
private long limit=1000000;//max memory in bytes 

public MemoryCache(){ 
    //use 50% of available heap size 
    setLimit(Runtime.getRuntime().maxMemory()/2); 
} 

public void setLimit(long new_limit){ 
    limit=new_limit; 
    Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB"); 
} 

public Bitmap get(String id){ 
    try{ 
     if(!cache.containsKey(id)) 
      return null; 
     //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 
     return cache.get(id); 
    }catch(NullPointerException ex){ 
     return null; 
    } 
} 

public void put(String id, Bitmap bitmap){ 
    try{ 
     if(cache.containsKey(id)) 
      size-=getSizeInBytes(cache.get(id)); 
     cache.put(id, bitmap); 
     size+=getSizeInBytes(bitmap); 
     checkSize(); 
    }catch(Throwable th){ 
     th.printStackTrace(); 
    } 
} 

private void checkSize() { 
    Log.i(TAG, "cache size="+size+" length="+cache.size()); 
    if(size>limit){ 
     Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated 
     while(iter.hasNext()){ 
      Entry<String, Bitmap> entry=iter.next(); 
      size-=getSizeInBytes(entry.getValue()); 
      iter.remove(); 
      if(size<=limit) 
       break; 
     } 
     Log.i(TAG, "Clean cache. New size "+cache.size()); 
    } 
} 

public void clear() { 
    cache.clear(); 
} 

long getSizeInBytes(Bitmap bitmap) { 
    if(bitmap==null) 
     return 0; 
    return bitmap.getRowBytes() * bitmap.getHeight(); 
} 

public boolean contains(String key) { 

    if(cache.containsKey(key)) { 
     return true; 
    } 

    return false; 
} 

}

답변

0

나는 이제 파일 스트림과 비트 맵으로 이미지를 얻는 대신에 꽤 좋은 방법을 발견했다. 나는 인터넷에서 다운로드 한 이미지에 대해, 원하는 모든 사람에게 코드로 드로어 블을 설정한다. 이미지를 다운로드하고 내부 메모리 또는 외부 메모리에 저장 한 다음 이미지 경로를 지정하기 만하면됩니다.

ImageView imageView = (ImageView) findViewById(R.id.image); 
File filePath = getFileStreamPath(fileName); 
imageView.setImageDrawable(Drawable.createFromPath(filePath)); 
+0

어떻게 메모리를 관리합니까 ??? –

+1

나는 그것에 대해 살펴 보지 못했지만 이미지를 메모리에로드하는 대신 이미지를 슬라이드 할 때마다 입력 스트림에서 이미지를 가져 오는 것만 같다고 생각합니다. 메모리에있는 것보다 훨씬 빠르기 때문입니다. – osayilgan

0

그것은 AsyncTask를 함께 할 수 없다. 비트 맵을보다 효율적으로 사용해야합니다. 비트 맵 OOM을 검색하십시오. 다운로드 한 이미지 샘플을 일부 샘플로 작성하십시오. here

Android SoftReference를 검색하십시오.

+0

비트 맵을 효율적으로 사용하려고했지만 이미지가 약 50KB이고 크기가 너무 작기 때문에 이미지를 사용하지 않는 것이 좋습니다. – osayilgan

0

비트 맵 캐시 관리를 위해이 링크를 사용해보십시오. outofMemory 예외를 방지하기위한 여러 가지 해결책이 있습니다. http://developer.android.com/training/displaying-bitmaps/index.html

+0

큰 이미지가 아닙니까? 내 이미지는 50-100KB 정도이므로,별로 중요하지 않다고 생각합니다. ??? – osayilgan

+0

비트 맵의 ​​크기가 아니라 얼마나 많은 비트 맵입니까? !! 오류가 발생하면 메모리에서 비트 맵을 제거한 다음 소프트 refrence를 제공하거나 sdcard에 저장하여 정확하게 관리해야합니다. Cos 메모리는 일반 장치에서는 16MB이므로 응용 프로그램을 많이 만들 때 응용 프로그램을 개발할 때 조심해야합니다. 그래서 더 나은 당신은 그 링크에 설명 된 방법 중 하나를 사용하십시오. :) –

+0

나는 가능한 한 빨리 그것을 시도하고 그것이 작동하는 경우 알려주지, 대답 bytheway 주셔서 감사합니다. – osayilgan

관련 문제