Reputation: 75
Each view of the viewpager had one image view with a Bitmap taken from url.
If I load small images - 100 X 80 px - I never get outofmemory, even if I load 10000 . If I load bigger images 800 X 60 px - I get outofmemory after 28 -30 images.
I see view pager recycles the images that are in a views , which have been swiped already. (when I swipe back quickly I see the images being loaded again .)
What I cannot figure out - why 10000 small images do not crash the app, but only 30 bigger images do it?
Please have a look at the code below:
<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;
}
}
}
}
Upvotes: 2
Views: 2265
Reputation:
you should refere to android Trainging Displaying Bitmaps Efficiently there they are telling you how to load images and without out of memory exception .
Hope taht helps
Upvotes: 0
Reputation: 15808
I am definitely not an expert in ViewPager
's inner mechanisms, but let's assume for a moment that it really properly recycles Bitmap
objects attached to the ImageView
instances you create for each fragment. My best guess, in this case, would be that, when you load smaller images the recycling mechanism does its magic before you hit the memory cap, so you never experience an OOME; however, when you load bigger images, the recycling mechanism is not able to prevent the OOME, because the chunks of memory you request are consuming available space quite a lot quicker.
This unsatisfactory guess aside, loading images in Android is a dreadful task, that I would try to delegate to libraries or some ready-made code solution rather than endure it myself. If you want to learn more about the task, there is a whole section in the official Training documentation dedicated to it, entitled Displaying Bitmaps Efficiently, which I would read, and read again from time to time, just to avoid forgetting how complex can become this stuff. The code attached to the documentation is even more involved, so it's a good read too.
Then, there are a couple of libraries apt to some use cases for image loading: you can check Picasso, Volley, and Android Universal Image Loader. I believe they all take care of downloading images, setting Bitmap
s to ImageView
s, proper resizing and recycling, and especially caching, in memory and on disk. I have personally used Picasso only, and found it satisfying enough for the task I had at hand.
Upvotes: 0
Reputation: 17735
I think that in destroyItem
you are detaching the ImageView
but the Event
objet still holds a reference to it, so it can not be garbage collected. Do you really need this reference ? (you create a new ImageView
each time).
By the way it's probably a good idea to shrink the images and to use a cache. Quite a few libraries can do that for you.
Upvotes: 0
Reputation: 49986
I think you should shrink your images, otherwise their processing requires to much memory causing OOM. For bigger images its more difficult to find long free address space, its easier for smaller images, you can find sample solution in this SO:
OutOfMemory while using AsyncTask and a large image
Upvotes: 1