Rohan Rohan - 1 month ago 23
Android Question

Out of Memory exception when clicking on a ListView item

I am trying to create a listview that has a background image for every element and a text view that shows up on top.
The list view populates fine, but clicking on the item directly throws an error.

Here's my list view element xml (menu_section.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="75dp">

<ImageView
android:id="@+id/section_bg_image"
android:layout_width="match_parent"
android:layout_height="75dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"/>


<TextView
android:id="@+id/section_title"
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_gravity="end"
android:background="@color/colorBlackTranslucent"
android:gravity="right|center_vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="Hello World"
android:textColor="@color/colorWhite"
android:textSize="24sp" />

</RelativeLayout>


This is my adapter MenuAdapter.java. I am loading images for the background from the assets folder. Each image is ~ 50Kb and right now there is a total of ~400Kb of images (with 8 items in the list)

import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.util.List;

import com.myapp.hotel.MyUtility;
import com.myapp.hotel.R;

public class MenuAdapter extends ArrayAdapter<MenuSection> {

Context context;
List<MenuSection> menuSections;
AssetManager assetManager;
String imageUrl;

public MenuAdapter(Context context, int resource, List<MenuSection> objects) {
super(context, resource, objects);
this.context = context;
this.menuSections = objects;
this.assetManager = context.getAssets();
}

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

@Override
public MenuSection getItem(int i) {
return menuSections.get(i);
}

@Override
public long getItemId(int i) {
return menuSections.indexOf(getItemId(i));
}

/* private view holder class */
private class ViewHolder {
ImageView menuSectionImage;
TextView menuSectionItemText;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;


LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (view == null) {
view = mInflater.inflate(R.layout.menu_section, null);
holder = new ViewHolder();
holder.menuSectionItemText = (TextView) view.findViewById(R.id.section_title);
holder.menuSectionImage = (ImageView) view.findViewById(R.id.section_bg_image);

view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}

MenuSection menuSection = menuSections.get(i);

holder.menuSectionItemText.setText(menuSection.getSectionName());

try {
imageUrl = menuSection.getImagePath();
if (!MyUtility.isNullOrEmpty(imageUrl)) {
Picasso.with(holder.menuSectionImage.getContext())
.load(Uri.parse(imageUrl))
.into(holder.menuSectionImage);
}
} catch (Exception ex) {
ex.printStackTrace();

}

return view;
}
}


and this is the Fragment RestaurantFragment.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.List;

import com.myapp.hotel.MyUtility;
import com.myapp.hotel.R;


/**
* A simple {@link Fragment} subclass.
*/
public class RestaurantFragment extends Fragment {
MenuAdapter adapter;
List<MenuSection> menuSections;
View view;

public RestaurantFragment() {
// Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(view == null) {
view = inflater.inflate(R.layout.fragment_restaurant, container, false);
}
//adapter = new ArrayAdapter<String>(RestaurantFragment.this.getContext(), R.layout.menu_view, R.id.menu_text, MyUtility.getMenuSections().toArray(new String[MyUtility.getMenuSections().size()]));
ListView listView = (ListView) view.findViewById(R.id.menu);
menuSections = MyUtility.getMenuSections();

adapter = new MenuAdapter(RestaurantFragment.this.getContext(), R.layout.menu_section, menuSections);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(RestaurantFragment.this.getActivity(), "Hello World",
Toast.LENGTH_SHORT).show();
}
});
//listView.setOnItemClickListener();
//listView.setAdapter(adapter);

/*
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent intent = new Intent(RestaurantFragment.this.getContext(), RestaurantMenuDetailsActivity.class);
intent.putExtra("menu_section", adapter.getItem(position).toString());
startActivity(intent);
}
});
*/
return view;
}
}


This is the error that I see in logcat

10-07 19:27:14.445 14925-14925/com.myapp.hotel E/InputEventReceiver: Exception dispatching input event.
10-07 19:27:14.445 14925-14925/com.myapp.hotel E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback
10-07 19:27:17.155 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10109874 byte allocation with 8141766 free bytes and 7MB until OOM"
10-07 19:27:18.195 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10109874 byte allocation with 8141862 free bytes and 7MB until OOM"
10-07 19:27:18.195 14925-14925/com.myapp.hotel E/MessageQueue-JNI: java.lang.StackOverflowError: stack size 8MB
10-07 19:27:19.695 14925-14925/com.myapp.hotel E/art: Throwing OutOfMemoryError "Failed to allocate a 10735842 byte allocation with 7722526 free bytes and 7MB until OOM"
10-07 19:27:20.255 14925-14925/? E/art: Throwing OutOfMemoryError "Failed to allocate a 10735842 byte allocation with 7722654 free bytes and 7MB until OOM"


What is it that I am missing/going wrong with?

UPDATE

All my images in total weight ~ 400Kb. 8 images of about 50 Kb each. The problem is that even if I comment out the entire image loading thing and just load the text, the same error is thrown on clicking any listview item. So its definitely not something to do with images. I think something is wrong with the Adapter.. just cannot figure out what it could be! Its just a simple adapter!

bwt bwt
Answer

I think it has nothing to do with the image handling. It's a stack overflow due to an infinite recursion in getItemId()

@Override
public long getItemId(int i) {
    // calls itself with the same value, it can not end well !
    return menuSections.indexOf(getItemId(i));
}
Comments