2013-12-26 3 views
1

У меня есть проблема, что у меня есть от 80 до 150 изображений с очень высоким разрешением, и я должен показать их в виде пейджера. Я написал простой механизм декодирования, но получаю OutofMemory Error после второй страницы. Я очень старался, но не смог найти точное решение, чтобы избежать этого. Мое собственное предположение заключается в том, что если мы сможем загружать изображение по частям в виде изображения, то, возможно, мы избегаем этого, но я не знаю, как этого добиться. Пожалуйста, предложите любое решение по этому вопросу.Отображение больших изображений в представлении pager из sdcard в android

Код:

private class MyPagerAdapter extends PagerAdapter { 

     @Override 
     public int getCount() { 
      return Integer.parseInt(pagesCount); 
     } 


     @Override 
     public boolean isViewFromObject(View arg0, Object arg1) { 
      return arg0==((ImageView)arg1); 
     } 
     @Override 
     public void destroyItem(View container, int position, Object object) { 
      View view = (View)object; 
       ((ViewPager) container).removeView(view); 
       view = null; 
     } 
     @Override 
     public View instantiateItem(View container, final int position) { 
      final ImageView imgPage = new ImageView(getApplicationContext()); 
      /*imgPage.setImageURI(Uri.withAppendedPath(
        Uri.parse(Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+issueName), "" + (issueName+position)+".png"));*/ 
      //imgPage.setImageBitmap(BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+issueName+"/"+(issueName+position))); 
      //destroyItem(container, position, imgPage); 
      imgPage.setScaleType(android.widget.ImageView.ScaleType.FIT_XY); 
      imgPage.setImageDrawable(getImageFromSdCard(issueName+position)); 
      //imgPage.setImageResource(getImageFromSdCard(issueName+position)); 


      ((ViewPager) container).addView(imgPage,0); 
      return imgPage; 
     } 
    } 


    public Drawable getImageFromSdCard(String imageName) { 
     Drawable d = null; 
     try { 
      String path = Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+"/"+magName+issueName; 
      bitmap = BitmapFactory.decodeFile(path + "/" + imageName 
        + ".png"); 

      // d = new BitmapDrawable(bitmap); 
      d = new BitmapDrawable(decodeFile(new File(path+"/"+imageName+".png"))); 
      // bitmap.recycle(); 
      bitmap = null; 
     } catch (IllegalArgumentException e) { 
      bitmap = null; 
     } 
     return d; 

    } 


    //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); 

      //The new size we want to scale to 
      final int REQUIRED_SIZE=550; 

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

      //Decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inSampleSize=scale; 
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); 
     } catch (FileNotFoundException e) {} 
     return null; 
    } 

Спасибо заранее.

+0

использование универсального загрузчика изображений https://github.com/nostra13/Android-Universal-Image-Loader/ – deadfish

+0

Спасибо Magnus за ваш ценный комментарий, но я уже использовал тот код, который вы поделили в своем комментарии. И ответ, которым я получил успех, принял то же самое. –

ответ

2

inJustDecodeBounds & inSampleSize

Вы декодирование изображений с высоким разрешением при каждом вызове PagerAdapter, и если вы готовы уменьшить декодированную память растрового по степеням 2 (х/2 х/4 ... х: оригинальный размер битовой карты), а затем перейти на этот method


Bitmap.recycle()

Очень удобный способ, когда он используется в нужном месте, может творить чудеса. Я предполагаю, что вы устанавливаете BitmapDrawable или вызываете setImageBitmap в ImageView. Добавьте следующий фрагмент в destroyItem() обратный вызов PagerAdapter.

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    View view = (View) object; 
    ImageView imageView = (ImageView) view.findViewById(R.id.image_view); 
    Drawable drawable = imageView.getDrawable(); 
    if(drawable instanceof BitmapDrawable) { 
     BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; 
     if(bitmapDrawable != null) { 
      Bitmap bitmap = bitmapDrawable.getBitmap(); 
      if(bitmap != null && !bitmap.isRecycled()) bitmap.recycle();  
     } 
    } 
    ((ViewPager) container).removeView(view); 
} 

Идея заключается в том, что когда какой-либо вид ребенка удаляется из пейджера, его растровый должно получить повторно, таким образом, вы не будете зависеть от GC требует, чтобы очистить память для вас.


largeHeap = истинный

Добавить эту недвижимость в Manifest.xml <application> теге.Везде, где поддерживается LargeHeap, он увеличит память кучи до некоторого большого значения, даже до 8 раз.


Кроме того, в общем случае не проводит никаких глупых ссылок на любое растровое изображение, просто расшифровать их и назначить его для просмотра, остальные будут заботиться.

Надеюсь, что это поможет. :)

0

Я предложу вам look at official android developers sample code called BitmapFun and use it for your purpose. На самом деле вы пропустили o2.inPurgable=true; Также нет необходимости использовать o и o2, o достаточно хорошо.

//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); 

      //The new size we want to scale to 
      final int REQUIRED_SIZE=550; 

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

      //Decode with inSampleSize 
      //BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o.inSampleSize=scale; 
      o.inJustDecodeBounds = false; 
      o.inPurgealbe = true; 
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o); 
     } catch (FileNotFoundException e) {} 
     return null; 
    } 
0

Удалите строку bitmap = BitmapFactory.decodeFile(path + "/" + imageName + ".png"); из метода Drawable getImageFromSdCard(String imageName), чтобы начать с. Также удалите переменную bitmap в этом методе, поскольку она не используется, теперь вы удалили ненужные выделения, проблема, которую вы испытываете, может заключаться в том, что GC просто не справляется с количеством мусора/распределений, которое было сделано, поскольку вы делали в два раза больше это было необходимо. Метод должен выглядеть примерно так:

public Drawable getImageFromSdCard(String imageName) { 
    Drawable d = null; 
    String path = Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+"/"+magName+issueName; 
    d = new BitmapDrawable(decodeFile(new File(path+"/"+imageName+".png"))); 
    return d; 
} 

также повторно использовать o переменный в decodeFile методы только не забудьте перевернуть булев inJustDecodeBounds после первого вызова.

Также не улавливайте исключения во время выполнения, плохая практика, они есть из-за ошибок времени выполнения. Ты скрываешь настоящую проблему, поймав их.

BitmapDrawable(Bitmap bitmap) конструктор устарел, так как api версия 4, checkout BitmapDrawable для какого конструктора вы должны использовать.

Смежные вопросы