将图像从网址加载到viewpager中 - outofmemory

时间:2014-01-26 09:10:58

标签: android image out-of-memory

viewpager的每个视图都有一个图像视图,其中一个Bitmap取自url。

如果我加载小图像 - 100 X 80 px - 即使我加载10000,我也永远不会忘记内存。 如果我加载更大的图像800 X 60 px - 我在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;

            } 




        }

    }



}

4 个答案:

答案 0 :(得分:1)

我认为你应该缩小你的图像,否则他们的处理需要大量的内存来导致OOM。对于更大的图像,更难找到长的自由地址空间,对于较小的图像更容易,你可以在这个SO中找到样本解决方案:

OutOfMemory while using AsyncTask and a large image

答案 1 :(得分:0)

我认为在destroyItem中您正在分离ImageView,但Event对象仍然引用它,因此无法进行垃圾回收。你真的需要这个参考吗? (每次都创建一个新的ImageView

顺便说一下,缩小图像和使用缓存可能是个好主意。相当多的图书馆可以为您做到这一点。

答案 2 :(得分:0)

我肯定ViewPager内部机制的专家,但我们暂时假设它确实正确地回收Bitmap附加到ImageView的对象您为每个片段创建的实例。在这种情况下,我最好的猜测是,当您加载较小的图像时,回收机制会在您触及内存上限之前发挥其魔力,因此您永远不会体验到OOME;但是,当您加载更大的图像时,回收机制无法阻止OOME,因为您请求的内存块消耗的可用空间要快得多。

除了令人不满意的猜测之外,在Android中加载图像是一项可怕的任务,我会尝试委托给库或一些现成的代码解决方案,而不是自己忍受。如果您想要了解有关该任务的更多信息,请参阅专门的官方培训文档中的一部分,标题为Displaying Bitmaps Efficiently,我会阅读,并不时再次阅读,以避免忘记复杂程度可以成为这个东西。附加到文档的代码甚至更复杂,所以它也是一个很好的阅读。

然后,有几个库可以用于图像加载的一些用例:你可以查看Picasso,Volley和Android Universal Image Loader。我相信他们都会负责下载图片,将Bitmap设置为ImageView,正确调整大小和回收,特别是在内存和磁盘上进行缓存。我个人只使用了毕加索,并且发现它足以满足我手头的任务。

答案 3 :(得分:0)

你应该参考android培训Displaying Bitmaps Efficiently 在那里,他们告诉你如何加载图像,没有内存不足的例外。

希望有所帮助