2014-01-26 41 views
2

viewpager的每個視圖都有一個圖像視圖,並帶有從url獲取的位圖。將url中的圖像加載到viewpager中 - outofmemory

如果我加載小圖像 - 100 X 80像素 - 我永遠不會失去內存,即使我加載10000。 如果我加載更大的圖像800×60像素 - 28 - 30圖像後,我得到outofmemory。

我看到視圖尋呼機回收已經被刷過的視圖中的圖像。 (當我趕緊刷卡後,我看到被再次載入圖像。)

我想不通 - 爲什麼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的內在機制方面的專家,但是讓我們假設一下,如果它真的妥善回收連接到您創建的每個片段ImageView實例Bitmap對象。在這種情況下,我最好的猜測是,當你加載較小的圖像時,回收機制在你打開內存蓋之前就會發揮它的魔力,所以你永遠不會遇到OOME;但是,當您加載更大的圖像時,回收機制無法阻止OOME,因爲您請求的內存塊大大快速地佔用可用空間。

這種不盡人意的猜測不談,在Android的加載圖像是一個可怕的任務,我會嘗試委派到圖書館或一些現成的代碼解決方案,而不是忍受它自己。如果您想了解更多關於此任務的信息,官方培訓文檔中有一整段內容專用於此,標題爲Displaying Bitmaps Efficiently,我會閱讀並不時閱讀,只是爲了避免忘記複雜程度可能會變成這種東西。附在文檔中的代碼更加涉及,所以它也是一個很好的閱讀。

然後,有一對夫婦庫容易一些用例圖像加載的:你可以檢查畢加索,排球,和Android通用圖像裝載機。我相信他們都會照顧下載圖像,將Bitmap設置爲ImageView,適當調整大小和回收,尤其是在內存和磁盤上進行緩存。我只親自使用過畢加索,並且發現它足以滿足我手邊的任務。

+0

畢加索的表現非常好 - 謝謝你,但是OOM仍然顯示,但是應用程序不會崩潰,奇怪的是 - OOM顯示的視圖編號與28完全相同 - 然後3個視圖開始再次顯示圖像,然後顯示幾個通常與圖像查看,然後再次3沒有圖像,這種方式永遠:)也許我應該減少這些圖像的確。 – BestSiteEditor

+0

@BestSiteEditor我認爲畢加索的API提供了一種方法,您可以將所需結果圖像的寬度和高度傳遞給它,並且它應該適當調整位圖以匹配這些參數。 –

+0

你是絕對正確的朱利奧,我目前正在探索畢加索提供的選擇,他們可以將它命名爲莫扎特 - 更好的功能,再次感謝。 – BestSiteEditor

1

我想你應該收縮你的圖片,否則他們的處理要求的內存造成OOM。對於更大的圖像其更難找到長期空閒的地址空間,它更容易爲更小的圖像,你可以找到在這個如此簡單的解決方案:

OutOfMemory while using AsyncTask and a large image

0

我認爲,在destroyItem你卸下ImageViewEvent objet仍然提及它,所以它不能被垃圾收集。你真的需要這個參考嗎? (您每次創建一個新的ImageView)。

順便說一句,收縮圖像和使用緩存可能是一個好主意。不少圖書館都可以爲你做到這一點。

+0

然而,據我所知,這是關聯到'ImageView',你需要回收,而不是'ImageView'本身'Bitmap'對象。因此,在這種情況下保持'ImageView'引用不會成爲問題,_if_與它們相關的'Bitmap'對象會被正確地回收,例如。通過一些'ViewPager'內部機制。 –

+0

感謝您的建議, – BestSiteEditor

+0

我曾嘗試在對象中設置位圖,稍後在某些視圖更改時回收它,但不幸的是無法執行此操作。例如,我看了YouTube的應用程序 - 成千上萬的圖像,大的,從來沒有OOM?!?! – BestSiteEditor

1

你應該參考安卓Trainging Displaying Bitmaps Efficiently 那裏他們告訴你如何加載圖像,並沒有內存不足的例外。

希望taht幫助

相關問題