1

In my app I have this error:

E/AndroidRuntime(16123): FATAL EXCEPTION: main
E/AndroidRuntime(16123): java.lang.RuntimeException: Unable to start activity ComponentInfo{it.bisemanuDEV.mathTools/it.bisemanuDEV.mathTools.MainActivity}: android.view.InflateException: Binary XML file line #58: Error inflating class <unknown>
E/AndroidRuntime(16123):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2073)
E/AndroidRuntime(16123):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2098)
E/AndroidRuntime(16123):    at android.app.ActivityThread.access$600(ActivityThread.java:138)
E/AndroidRuntime(16123):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1204)
E/AndroidRuntime(16123):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(16123):    at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(16123):    at android.app.ActivityThread.main(ActivityThread.java:4872)
E/AndroidRuntime(16123):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(16123):    at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(16123):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
E/AndroidRuntime(16123):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
E/AndroidRuntime(16123):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(16123): Caused by: android.view.InflateException: Binary XML file line #58: Error inflating class <unknown>
E/AndroidRuntime(16123):    at android.view.LayoutInflater.createView(LayoutInflater.java:613)
E/AndroidRuntime(16123):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
E/AndroidRuntime(16123):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:660)
E/AndroidRuntime(16123):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
E/AndroidRuntime(16123):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)

05-11 20:21:56.843: E/AndroidRuntime(16123): at android.view.LayoutInflater.rInflate(LayoutInflater.java:749) E/AndroidRuntime(16123): at android.view.LayoutInflater.inflate(LayoutInflater.java:489) E/AndroidRuntime(16123): at android.view.LayoutInflater.inflate(LayoutInflater.java:396) E/AndroidRuntime(16123): at android.view.LayoutInflater.inflate(LayoutInflater.java:352) E/AndroidRuntime(16123): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:361) E/AndroidRuntime(16123): at android.app.Activity.setContentView(Activity.java:2043) E/AndroidRuntime(16123): at it.bisemanuDEV.mathTools.MainActivity.onCreate(MainActivity.java:27) E/AndroidRuntime(16123): at android.app.Activity.performCreate(Activity.java:5191) E/AndroidRuntime(16123): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1082) E/AndroidRuntime(16123): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2037) E/AndroidRuntime(16123): ... 11 more E/AndroidRuntime(16123): Caused by: java.lang.reflect.InvocationTargetException E/AndroidRuntime(16123): at java.lang.reflect.Constructor.constructNative(Native Method) E/AndroidRuntime(16123): at java.lang.reflect.Constructor.newInstance(Constructor.java:417) E/AndroidRuntime(16123): at android.view.LayoutInflater.createView(LayoutInflater.java:587) E/AndroidRuntime(16123): ... 25 more E/AndroidRuntime(16123): Caused by: java.lang.OutOfMemoryError E/AndroidRuntime(16123): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) E/AndroidRuntime(16123): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:500) E/AndroidRuntime(16123): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:353) E/AndroidRuntime(16123): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:781) E/AndroidRuntime(16123): at android.content.res.Resources.loadDrawable(Resources.java:1969) E/AndroidRuntime(16123): at android.content.res.Resources.getDrawable(Resources.java:673) E/AndroidRuntime(16123): at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173) E/AndroidRuntime(16123): at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:881) E/AndroidRuntime(16123): at android.graphics.drawable.Drawable.createFromXml(Drawable.java:818) E/AndroidRuntime(16123): at android.content.res.Resources.loadDrawable(Resources.java:1954) E/AndroidRuntime(16123): at android.content.res.TypedArray.getDrawable(TypedArray.java:601) E/AndroidRuntime(16123): at android.view.View.(View.java:3347) E/AndroidRuntime(16123): at android.widget.TextView.(TextView.java:494) E/AndroidRuntime(16123): at android.widget.Button.(Button.java:107) E/AndroidRuntime(16123): at android.widget.Button.(Button.java:103) E/AndroidRuntime(16123): ... 28 more

What can be the solution?

bisemanu
  • 441
  • 2
  • 9
  • 19
  • Calculate Sample size before decoding resource.. – Pragnani May 10 '13 at 15:40
  • It's a basic memory error while handling Bitmaps. Look up this site: http://developer.android.com/training/displaying-bitmaps/index.html and even more http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html – DigCamara May 10 '13 at 15:40

3 Answers3

2

Your application memory is growing up too fast... This is how Android manages its memory per application: Lets say when you start your application, it has 10MB of memory. When your application uses for example 8MB, Android predicts that the remaining 2MB may not be sufficient. So Android gives your application some additional memory. So now you have 13MB (for example). This scenario repeats each time Android decides that the remainging memory may not be enough for your application. This way the used memory from the application is growing slowly and Android can manage it more effectively.

In your example you have a loop that is decoding images. This way the size of memory that your application uses grows too fast and Android has no time to gives you more memory.

Kiril Aleksandrov
  • 2,601
  • 20
  • 27
1

The message is pretty self explanatory... You're running out of memory.

Check the parameters that you're passing to this method, there might simply be too many bitmaps being decoded and stored in memory.

Consider caching instead of pre-loading all the bitmaps - only load the bitmap when you actually need to use it. Then add it to a hasmap (from its ID to the actual bitmap). Before decoding a bitmap check if it is already in the map, if it is you don't need to decode it again. Be sure to check the size of the map before decoding new bitmaps, and clear the cache when necessary so you don't run out of memory.

Edit: Here's an example for how you could do it

Edit2: Here's the full class code. Hope I didn't make any typos.

public class CurrencyRateListAdapter extends BaseAdapter {
    // This variable is used for debug log (LogCat)
    private static final String TAG = "CC:CurrencyRateListAdapter";

    private LayoutInflater mInflater;
    private String[] mName; 
    private Integer[] mBitmapIds;
    private HashMap<Integer, Bitmap> mBitmaps;
    private Context mContext;

    private Cursor   mRateData;
    private double   mRate[];
    private String   mDisplayrate[];

    private int      mBaseCurrencyPosition;

    public CurrencyRateListAdapter(Context context, Integer[] name, Integer[] bitmapID, Cursor rate_data) {
        mInflater = LayoutInflater.from(context);
        mBitmaps = new HashMap<Integer, Bitmap>();
        mBitmapIds = bitmapID;
        mContext = context;
        mName = new String[name.length];

        for(int j=0; j<name.length; j++) {
            mName[j] = context.getString(name[j]);
        }

        mRateData = rate_data;

        // update currency rate
        updateCurrencyRate();

        // set default currency
        mBaseCurrencyPosition = 0;
    }

    @Override
    public void finalize() {
        Log.d(TAG, "Close SQL cursor...");
        mRateData.close();
    }

    public int getCount() {
        return mBitmapIds.length;
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder  holder;             

        //Log.d(TAG, ">>>>> getView: position=" + Integer.toString(position));

        try {
            if(convertView == null) {
                // uses currencyratelist.xml to display each currency selection
                convertView = mInflater.inflate(R.layout.currencyratelist, null);
                // then create a holder for this view for faster access
                holder = new ViewHolder();

                holder.icon = (ImageView) convertView.findViewById(R.id.ratelist_icon);
                holder.name = (TextView) convertView.findViewById(R.id.ratelist_text);
                holder.rate = (TextView) convertView.findViewById(R.id.ratelist_ratetext);

                // store this holder in the list
                convertView.setTag(holder);
            } else {
                // load the holder of this view
                holder = (ViewHolder) convertView.getTag();
            }

            holder.icon.setImageBitmap(getIcon(mBitmapIds[position]));
            holder.name.setText(mName[position]);
            holder.rate.setText(mDisplayrate[position]);

        } catch (Exception e) {
            Log.e(TAG, "getView:" + e.toString());
        }

        //Log.d(TAG, "<<<<< getView: position=" + Integer.toString(position));

        return convertView;
    }

    public void SetBaseCurrencyIndex(int value) {
        mBaseCurrencyPosition = value;

        // update display rate
        double  rate_base = 1.0;

        if(mBaseCurrencyPosition < mRate.length) {
            rate_base = mRate[mBaseCurrencyPosition];
        }

        mDisplayrate = new String[mRateData.getCount()];

        for(int i=0; i<mRateData.getCount(); i++) {
            mDisplayrate[i] = String.format(Locale.US, "%.3f", mRate[i] / rate_base);
        }
    }

    public String getDisplayString(int position) {
        String result = "1.000";

        if(position < mRate.length) {
            result = mDisplayrate[position];
        }

        return result;
    }

    public void updateCurrencyRate() {
        Log.d(TAG, ">>>>> updateCurrencyRate");

        // update currency rate data
        mRateData.requery();

        mRate = new double[mRateData.getCount()];

        int cnt = mRateData.getCount();
        int colcnt = mRateData.getColumnCount();

        for(int i=0; i<cnt; i++) {
            if(mRateData.moveToPosition(i) == true) {
                if(colcnt == 1) {
                    // only currency rate data in the query result set
                    mRate[i] = mRateData.getDouble(0);
                } else {
                    // all data in the query result set
                    // So the rate data in the 2nd column (refer to CurrencyConverterDB class
                    mRate[i] = mRateData.getDouble(1);
                }
            } else {
                mRate[i] = 1.0;
            }
        }

        // deactive currency rate data
        mRateData.deactivate();

        Log.d(TAG, "<<<<< updateCurrencyRate");
    }   

    public double getCurrencyRate(int position) {
        double rate_sel = 1.0;

        if(position < mRate.length) {
            rate_sel = mRate[position];
        }

        return rate_sel;
    }

    /* class ViewHolder */
    private class ViewHolder {
        ImageView   icon;
        TextView    name;
        TextView    rate;
    }

    private Bitmap getIcon(Integer bitmapId) {
        Bitmap icon = mBitmaps.get(bitmapId);

        if (icon == null) {
            icon = BitmapFactory.decodeResource(mContext.getResources(), bitmapId);
            mBitmaps.put(bitmapId, icon);
        }

        return icon;
    }   
}
tbkn23
  • 5,205
  • 8
  • 26
  • 46
  • Could I clean the memory every time I go out from the app? – bisemanu May 10 '13 at 16:55
  • what is the instruction to do this? – bisemanu May 10 '13 at 18:56
  • 1
    If you implement a `HashMap` like I proposed, it has a `clear()` method. – tbkn23 May 10 '13 at 18:57
  • 1
    A LruCache is what you really want here : it is a cache that will automatically delete its least used elements when it gets bigger than it is allowed to. – Teovald May 10 '13 at 19:16
  • I wasn't familiar with that but it sounds even better. – tbkn23 May 10 '13 at 19:21
  • I edited the code with what I'm using now, but the listview is not properly loaded – bisemanu May 11 '13 at 11:15
  • The idea was not to load all icons at once. Only call `getIcon()` when you actually need to use the icon, from your activity or whatnot – tbkn23 May 11 '13 at 11:46
  • the problem is right there, I need to load the icons all at once, as soon as I open the application, to fill the listwiev – bisemanu May 11 '13 at 12:33
  • i posted whole the code of java class CurrencyRateListAdapter, that recall in ActivityMain with the code already posted. – bisemanu May 11 '13 at 16:00
  • 1
    you do not need to load all the icons into memory at once. Instead, from the `getView()` method, call `getIcon()`. I'll update the answer with the full code. – tbkn23 May 11 '13 at 18:04
  • This is unrelated. Create a new question and post your layout XML – tbkn23 May 11 '13 at 20:57
0

you are getting java.lang.OutOfMemoryError because you are running this for loop

for(int i=0; i<bitmapID.length; i++) {
mIcon[i] = BitmapFactory.decodeResource(context.getResources(), bitmapID[i].intValue());

}

Note that decodeResource can cause that. I suggest you to try alternative ways as this function really takes lots of memory.

you may also want to calculate the size you need and than decode. in most cases you don't really need the full size.

Udi Oshi
  • 6,787
  • 7
  • 47
  • 65
  • How should I proceed to do what you suggest? – bisemanu May 10 '13 at 15:48
  • before you need to decode, calculate only the size you need and than decode the bitmap. it will decrease your memory. check the links above it can help you decide what you want to do with your bitmaps. – Udi Oshi May 10 '13 at 15:53
  • how should I proceed to do what you suggest? are not an expert unfortunately – bisemanu May 10 '13 at 16:20
  • read this documentation about your error, it will help you decide how to handle this error correctly: http://developer.android.com/training/displaying-bitmaps/index.html. it contains lessons on how to handle in the UI. – Udi Oshi May 10 '13 at 16:22
  • Could I clean the memory every time I go out from the app? – bisemanu May 10 '13 at 16:42
  • @bisemanu its the job of the garbage collector to free memory.http://www.youtube.com/watch?v=_CruQY55HOk. you could use a lazy list or UIL http://stackoverflow.com/questions/15621936/whats-lazylist. http://www.youtube.com/watch?v=wDBM6wVEO70 – Raghunandan May 10 '13 at 17:45