2014-01-26 3 views
2

Каждый вид viewpager имел один вид изображения с растровым изображением, взятым из url.Загрузка изображений с url в viewpager - outofmemory

Если я загружаю небольшие изображения - 100 X 80 px - я никогда не получаю outofmemory, даже если я загружаю 10000. Если я загружаю большие изображения 800 X 60 px - я получаю outofmemory после 28 -30 изображений.

Я вижу, что просмотр пейджера перерабатывает изображения, которые находятся в виде, которые уже были вырезаны. (когда я быстро откидываюсь назад, я вижу, что изображения загружаются снова.)

Что я не могу понять - почему 10000 маленьких изображений не разбивают приложение, но это только 30 больших изображений?

Пожалуйста, посмотрите на код ниже:

<PRE> 

public class MainActivity extends FragmentActivity implements OnClickListener { 
    final String appurl = "http://drafts.bestsiteeditor.com/cgi-bin/bookcalendar/promoters.pl"; 
    final String imgurl = "http://drafts.bestsiteeditor.com/promoters/"; 
    ArrayList<Event> events = new ArrayList<Event>(); 
    ViewPager mPager; 
    GetServerData mt; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
     cal.set(Calendar.HOUR_OF_DAY, 0);cal.set(Calendar.MINUTE, 0);cal.set (Calendar.SECOND, 0);cal.set(Calendar.MILLISECOND, 0); 
     int monday = (int) (cal.getTimeInMillis()/1000); 
     if (cal.get(Calendar.DAY_OF_WEEK) == 2) {} else {for (int d = 1; d <= 7; d++) {monday = monday - 86400;cal.setTimeInMillis((long) monday * 1000);if (cal.get(Calendar.DAY_OF_WEEK) == 2) {break;}}} 

     makeWeek(monday); 

     mPager = (ViewPager) findViewById(R.id.pager); 


    } 


    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 

     return ActionBar.HandleMenu(this, item.getItemId()); 

    } 

    @Override 
    public void onClick(View v) { 

     // if (v == show_calendar) { 
     // Intent openMenu; 
     // openMenu = new Intent(this, WeekCalendar.class); 
     // startActivity(openMenu); 

     // } 

    } 

    public class CustomPagerAdapter extends PagerAdapter { 

     ArrayList<Event> events; 
     LayoutInflater inflater; 
     Context c; 

     public CustomPagerAdapter(Context context, ArrayList<Event> events) { 
      this.inflater = (LayoutInflater) context 
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      this.events = events; 
      this.c = context; 
     } 

     @Override 
     public boolean isViewFromObject(View view, Object object) { 
      return view == ((RelativeLayout) object); 
     } 

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

     @Override 
     public void destroyItem(View container, int position, Object object) { 
      // ((ViewPager) container).removeView((View)object); 
      System.out.println("DESTROY destroying view at position " 
        + position); 
      View view = (View) object; 

      ((ViewPager) container).removeView(view); 
      view = null; 

     } 

     @Override 
     public Object instantiateItem(ViewGroup container, int position) { 

      View itemView; 
      itemView = inflater.inflate(R.layout.first_frag, container, false); 
      Event e = events.get(position); 

      TextView topTextItem = (TextView) itemView.findViewById(R.id.tvFragFirst); 
      TextView bottomTextItem = (TextView) itemView.findViewById(R.id.tv2); 
      ImageView iv = (ImageView) itemView.findViewById(R.id.imageView1); 
      e.setImageView(iv); 
      //if (position == 0) { 
       ShowImage shim = new ShowImage(imgurl + "th" + e.getId()+ "1.jpg", iv,c); 
       shim.execute(); 
      //} 

      Button btn = (Button) itemView.findViewById(R.id.button1); 
      final String showtoast = String.valueOf(events.size()); 
      btn.setOnClickListener(new Button.OnClickListener() { 
       public void onClick(View v) { 
        Toast.makeText(getBaseContext(), 
          "Event expired before:" + showtoast, 
          Toast.LENGTH_LONG).show(); 
       } 
      }); 


      topTextItem.setText(e.getDsc()); 
      bottomTextItem.setText(String.valueOf(position) + e.getTitle()); 

      ((ViewPager) container).addView(itemView); 

      return itemView; 
     } 

    } 



    public class Event { 
     String id; 
     String title; 
     String description; 
     ImageView iv; 

     public Event(String id, String ttl, String dsc) { 
      this.id = id; 
      this.title = ttl; 
      this.description = dsc; 
     } 

     public void setImageView(ImageView niv) { 
      this.iv = niv; 
     } 

     public String getId() { 
      return id; 
     } 

     public String getTitle() { 
      return title; 
     } 

     public String getDsc() { 
      return description; 
     } 

     public ImageView getIV() { 
      return iv; 
     } 
    } 

    public class Pair { 
     public String isonline; 
     public ArrayList<Event> events; 

    } 

    private class GetServerData extends AsyncTask<Void, Void, Pair> { 

     Context context; 
     String targetUrl; 
     String imgUrl; 

     public GetServerData(Context context, String url, String imgurl) { 
      this.context = context; 
      this.targetUrl = url; 
      this.imgUrl = imgurl; 

     } 

     @Override 
     protected Pair doInBackground(Void... params) { 


      ArrayList<Event> eventsar = new ArrayList<Event>(); 

      String isonline = "no"; 
      Event newevent = null; 

      Document doc; 
      try { 

       doc = Jsoup.connect(targetUrl).get(); 
       isonline = doc.select("div#isonline").text(); 

       Elements promoters = doc.select("div.promoters"); 
       Elements events = doc.select("div.events"); 
       Elements eventsfull = doc.select("div.eventsfull"); 

       if (eventsfull.size() > 0) { 
        for (Element event : eventsfull) { 
         String temp = event.text().toString(); 
         String title = event.select("div.title").text(); 
         String event_id = event.select("div.event_id").text(); 

         String promoter_id = event.select("div.promoter_id") 
           .text(); 

         String promoter_name = event.select("div.promoter_name").text(); 
         String promoter_email = event.select("div.promoter_email").text(); 
         String promoter_phone = event.select("div.promoter_phone").text(); 
         String promoter_dsc = event.select("div.promoter_dsc").text(); 
         Integer imgs = Integer.parseInt(event.select("div.event_images").text()); 

         String[] eventSplit = temp.split("\\|"); 

         newevent = new Event(event_id, title, promoter_dsc); 
         eventsar.add(newevent); 

        } 
       } 

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

      Pair p = new Pair(); 
      p.isonline = isonline; 
      p.events = eventsar; 

      return p; 

     } 

     @Override 
     // protected void onPostExecute(ArrayList<Integer> rows) { 
     protected void onPostExecute(Pair p) { 
      String isonline = p.isonline; 
      events = p.events; 

      if (isOnline()) { 

       if (isonline.equals("yes")) { 

        Calendar clt = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
        Long nowt = clt.getTimeInMillis(); 

    CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(context, events);mPager.setAdapter(customPagerAdapter); 

        // mPager.setOffscreenPageLimit(4); 

       } else { 

        Toast.makeText(getApplicationContext(), 
          "No Internet Connection with this page.",Toast.LENGTH_LONG).show(); 
       } 
      } else { 
       Toast.makeText(getApplicationContext(),"No Internet Connection at all.", Toast.LENGTH_LONG).show(); 
      } 
     } 

    } 

    public boolean isOnline() { 
     ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo netInfo = cm.getActiveNetworkInfo(); 
     if (netInfo != null && netInfo.isConnectedOrConnecting()) { 
      return true; 
     } 
     return false; 
    } 

    public void makeWeek(Integer start_day) { 
     try { 
      Random rand = new Random(); 
      int myRandom = rand.nextInt() % 3; 
      mt = new GetServerData(MainActivity.this, appurl+ "?action=getevents&weekmonday=" + start_day + "&rand="+ myRandom, imgurl); 
      mt.execute(); 

     } catch (Exception e) { 
     } 
    } 

    private class ShowImage extends AsyncTask<Void, Void, Bitmap> { 
     ImageView imgV; 
     String imgsrc; 
     Bitmap d; 
     Context c; 



     public ShowImage(String src, final ImageView v,Context cntx) { 
      this.imgV = v; 
      this.imgsrc = src; 
      this.c=cntx; 
     } 

     @Override 
     protected Bitmap doInBackground(Void... params) { 
      //InputStream is = null; 
      //try { 
       // is = (InputStream) new URL(imgsrc).getContent(); 

       //URL url = new URL(imgsrc); 
       //d = BitmapFactory.decodeStream(url.openConnection() 
         //.getInputStream()); 

      //} catch (MalformedURLException e) { 
       //e.printStackTrace(); 
      //} catch (IOException e) { 
       //e.printStackTrace(); 
      //} 

      InputStream in = null; 

       try{ 
        HttpClient httpclient = new DefaultHttpClient(); 
        HttpResponse response = httpclient.execute(new HttpGet(imgsrc)); 
        in = response.getEntity().getContent(); 
       } catch(Exception e){ 
        e.printStackTrace(); 
       } 
       try { 


        d = BitmapFactory.decodeStream(in); 
       } finally { 
        if (in != null) { try { 
         in.close(); 
        } catch (IOException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } } 
       } 




      return d; 
     } 

     @Override 
     protected void onPostExecute(Bitmap dr) { 

      imgV.setImageBitmap(dr); 

      if (dr != null) { 

       dr=null; 

      } 




     } 

    } 



} 

ответ

0

Я определенно не эксперт в области внутренних механизмов ViewPager «s, но давайте предположим на минуту, что это действительно правильно перерабатывает Bitmap объекты, прикрепленные к ImageView экземпляров, созданных для каждого фрагмента. Мое лучшее предположение, в данном случае, было бы в том, что когда вы загружаете меньшие изображения, механизм рециркуляции делает свою магию, прежде чем вы нажмете крышку памяти, чтобы вы никогда не испытывали OOME; однако, когда вы загружаете большие изображения, механизм рециркуляции не может предотвратить OOME, потому что куски памяти, которые вы запрашиваете, потребляют доступное пространство намного быстрее.

Это неудовлетворительное предположение, загрузка изображений на Android - это ужасная задача, которую я бы попытался делегировать библиотекам или готовому кодовому решению, а не терпеть его сам. Если вы хотите узнать больше о задаче, в официальной учебной документации, посвященной этому, есть целый раздел, который называется «Displaying Bitmaps Efficiently», который я читал и время от времени читал, просто чтобы не забыть, насколько сложным может стать этот материал , Код, прикрепленный к документации, еще более задействован, поэтому он тоже хорошо читается.

Тогда есть несколько библиотек, подходящих для некоторых случаев для загрузки изображений: вы можете проверить Picasso, Volley и Android Universal Image Loader. Я считаю, что все они заботятся о загрузке изображений, установив Bitmap s в ImageView s, правильное изменение размера и повторное использование, и особенно кеширование, в памяти и на диске. Я лично использовал только Пикассо, и нашел, что это достаточно удовлетворительно для моей задачи.

+0

Пикассо ведет себя великолепно - спасибо, но все же OOM показывает, НО приложение не падает, и что странно - OOM показывает точно так же, как и номер 28, а затем после того, как 3 представления начинают показывать изображения снова, а затем показывают несколько изображений обычно отображаются с изображениями, а затем снова 3 без изображений, и таким образом навсегда :) Может быть, я должен уменьшить эти изображения. – BestSiteEditor

+0

@BestSiteEditor Я думаю, API API Picasso имеет метод, по которому вы передаете ширину и высоту желаемого результирующего изображения, и он должен соответствующим образом изменить размер растрового изображения в соответствии с этими параметрами. –

+0

Ты совершенно прав Джулио, я в настоящее время изучаю варианты, предоставленные Пикассо, они могли бы назвать его Моцартом - лучше с этой функциональностью, Еще раз спасибо. – BestSiteEditor

1

Я думаю, вы должны уменьшить ваши изображения, в противном случае их обработка требует много памяти, вызывая ООМ. Для больших изображений его более трудно найти длинное свободное адресное пространство, его проще для небольших изображений, вы можете найти решение образца в этом так:

OutOfMemory while using AsyncTask and a large image

0

Я думаю, что в destroyItem вы отсоединение ImageView но Event objet все еще содержит ссылку на него, поэтому он не может быть собранным мусором. Вам действительно нужна эта ссылка? (каждый раз вы создаете новый ImageView).

Кстати, это, вероятно, хорошая идея сжать изображения и использовать кеш. Для вас это может сделать несколько библиотек.

+0

Однако, AFAIK, это 'Bitmap' объект, связанный с' ImageView', что вам нужно утилизировать, а не 'самой ImageView'. Таким образом, поддержание ссылок «ImageView» не будет проблемой в этом случае, если объекты, связанные с ними, будут правильно переработаны, например. с помощью некоторого внутреннего механизма ViewPager. –

+0

Спасибо за советы, – BestSiteEditor

+0

Я попытался установить растровое изображение в объекте, а затем переработать его при изменении какого-либо вида, но не смог сделать это, к сожалению. Например, я смотрю приложение youtube - тысячи изображений, и большой, и никогда не OOM?!?! – BestSiteEditor

1

Вы должны обратиться к android Trainging Displaying Bitmaps Efficiently там они расскажут вам, как загружать изображения и исключать из памяти.

Надежда TAHT помогает

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