0

I'm a beginner in Android dev. I'm trying to make a wallpaper app. Shows a splash Screen for 2sec, and then shifts to the grid view where I've displayed 15 images. Many errors show up when to goes to this MainActivity showing the grid layout. The app is about 5 mb. is that the problem ? Please Help.

Here's the LogCat as soon as this activity starts.

09-01 01:07:05.134: E/dalvikvm-heap(6811): Out of memory on a 16384016-byte allocation.
09-01 01:07:05.144: E/AndroidRuntime(6811): FATAL EXCEPTION: main
09-01 01:07:05.144: E/AndroidRuntime(6811): java.lang.OutOfMemoryError
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:503)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:356)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:800)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.content.res.Resources.loadDrawable(Resources.java:2105)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.content.res.Resources.getDrawable(Resources.java:695)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.ImageView.resolveUri(ImageView.java:636)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.ImageView.setImageResource(ImageView.java:365)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at com.gamerspitch.dbzwallapper.ImageAdapter.getView(ImageAdapter.java:58)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.AbsListView.obtainView(AbsListView.java:2177)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.GridView.makeAndAddView(GridView.java:1341)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.GridView.makeRow(GridView.java:341)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.GridView.fillDown(GridView.java:283)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.GridView.fillFromTop(GridView.java:417)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.GridView.layoutChildren(GridView.java:1229)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.AbsListView.onLayout(AbsListView.java:2012)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.View.layout(View.java:14289)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewGroup.layout(ViewGroup.java:4559)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.View.layout(View.java:14289)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewGroup.layout(ViewGroup.java:4559)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:349)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.View.layout(View.java:14289)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewGroup.layout(ViewGroup.java:4559)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.View.layout(View.java:14289)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewGroup.layout(ViewGroup.java:4559)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1976)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1730)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.Choreographer.doCallbacks(Choreographer.java:562)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.Choreographer.doFrame(Choreographer.java:532)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.os.Handler.handleCallback(Handler.java:730)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.os.Handler.dispatchMessage(Handler.java:92)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.os.Looper.loop(Looper.java:137)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at android.app.ActivityThread.main(ActivityThread.java:5103)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at java.lang.reflect.Method.invokeNative(Native Method)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at java.lang.reflect.Method.invoke(Method.java:525)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
09-01 01:07:05.144: E/AndroidRuntime(6811):     at dalvik.system.NativeStart.main(Native Method)

MainActivity.java

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.grid_layout);

    GridView gridView = (GridView) findViewById(R.id.grid_view);

    // Instance of ImageAdapter Class
    gridView.setAdapter(new ImageAdapter(this));

    gridView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View v,
                int position, long id) {

            // Sending image id to FullScreenActivity
            Intent i = new Intent(getApplicationContext(), FullImageActivity.class);
            // passing array index
            i.putExtra("id", position);
            startActivity(i);
        }
    });
}

ImageAdapter.java

public class ImageAdapter extends BaseAdapter {

private Context mContext;

// Keep all Images in array
public Integer[] mThumbIds = { R.drawable.pic1, R.drawable.pic2, 
        R.drawable.pic3, R.drawable.pic4, R.drawable.pic5,
        R.drawable.pic6, R.drawable.pic7, R.drawable.pic8,
        R.drawable.pic9, R.drawable.pic10, R.drawable.pic11,
        R.drawable.pic12, R.drawable.pic13, R.drawable.pic14,
        R.drawable.pic15, R.drawable.pic16 };


public ImageAdapter(Context c) {
    mContext = c;
}

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

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

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

// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    if (convertView == null) 
    {  
        Resources r = Resources.getSystem();
        float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120, r.getDisplayMetrics());
        // if it's not recycled, initialize some attributes
        imageView = new ImageView(mContext);
        imageView.setLayoutParams(new GridView.LayoutParams(LayoutParams.WRAP_CONTENT, (int)px));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        //imageView.setPadding(8, 8, 8, 8);
    } else {
        imageView = (ImageView) convertView;
    }

    imageView.setImageResource(mThumbIds[position]);
    return imageView;
}

}

grid_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grid_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background2"
android:padding="10dp"
android:numColumns="auto_fit"
android:columnWidth="90dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:gravity="center"
android:stretchMode="columnWidth" >


</GridView>

Please help me on this, or explain to me why exactly I'm getting those errors. Thanks in advance.

Abhijit
  • 41
  • 2
  • 9
  • use lazy loading http://stackoverflow.com/questions/15621936/whats-lazylist. Use Universal Image Loader. or try the sample Bitmapfun from http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. Download the zip file and try it. – Raghunandan Aug 31 '13 at 19:51
  • Thanks for the solution. Now I'll have to dig deep into this lazy loading first. – Abhijit Aug 31 '13 at 20:05
  • you can check the sample bitmapfun from the second link posted. if you don't want to use a third party library. – Raghunandan Aug 31 '13 at 20:07

3 Answers3

2

Basically you are loading TOOOOO many images in your gridview. my advice to you is to put your pictures online and then Use ImageLoader to cache your image so they can be available offline as well. It will provide smooth scrolling and faster loading!

https://github.com/thest1/LazyList

Omar Farhat
  • 668
  • 4
  • 15
  • Got it. But if possible, could you share a link for a detailed procedure of loading bitmaps and images through lazy loading? Thanks Anyway – Abhijit Aug 31 '13 at 20:06
  • i will detail everything in a second answer. – Omar Farhat Aug 31 '13 at 20:08
  • @Abhijit check this http://stackoverflow.com/questions/16789676/caching-images-and-displaying/16978285#16978285 for universal image loader (except use gridview instead of listview) but i suggest you look at the sample @ http://developer.android.com/training/displaying-bitmaps/load-bitmap.html – Raghunandan Aug 31 '13 at 20:09
  • @KingOmar delete your duplicate answer. or it may be flagged and deleted. you can edit your answer post the update – Raghunandan Aug 31 '13 at 20:18
  • 1
    putting the images online has nothing to do with RAM usage . it got OOM . this is not a correct answer. the source of where you get the images from doesn't matter at all. what matters is how many bytes does each bitmap takes. – android developer Aug 31 '13 at 20:54
1
  1. Upload all images online. Not Hard.
  2. Then Copy all the classes from LazyList github project to your app. Just copy the codes or create a new package and paste the classes there.
  3. Now you need to modify this code right here

    public Integer[] mThumbIds = { R.drawable.pic1, R.drawable.pic2, 
            R.drawable.pic3, R.drawable.pic4, R.drawable.pic5,
            R.drawable.pic6, R.drawable.pic7, R.drawable.pic8,
            R.drawable.pic9, R.drawable.pic10, R.drawable.pic11,
            R.drawable.pic12, R.drawable.pic13, R.drawable.pic14,
            R.drawable.pic15, R.drawable.pic16 

};

To

public String[] avariable = {urlforimage1, urlforimage2,blabla};

Then Just type, ImageLoader.displayImage(avariable[position], imageview);

Don't forget constructor as well.

Omar Farhat
  • 668
  • 4
  • 15
1

the answers others have given you about putting the images on a server aren't correct at all. it doesn't matter if it's in the app or on a server since in the end, you need images to be decoded.

size of the app doesn't matter about the images, as it depends on their resolutions and where you put them. a jpg file could take a lot less than the memory that is needed in order to show it, especially if it doesn't have a lot of randomness on the pixels.

as an example, if you put a 1000x1000 image in the "res/drawable" folder (which is mdpi), and you run the app on an xhdpi device (like galaxy s3) , it would take

(1000*2)*(1000*2)*4=16,000,000 bytes ~ 16MB per image

if you decode 16 of those, you use 256,000,000 bytes . that's right - 256 MB , which is a lot of RAM just for images.

the situation will be even worse on an xxhdpi device (like galaxy s4 and HTC one ) :

16*(1000*3)*(1000*3)*4 = 576,000,000 ~ 576 MB ...

what can you do? actually i've answered a very similar question here. in short, you can downscale to the size that you need to , and/or use a different config . you could also put the images in the drawable-xhdpi folder .

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • Perfect man. I just copied those images into xhdpi folder, and it worked like a charm on nexus 4. Thank you But should I have to copy those images to hdpi, ldpi and mdpi? trying to avoid that coz it'll just increase app size :/ – Abhijit Sep 01 '13 at 04:51
  • putting images on the other dpi folders would increase the app size, but will also avoid scaling of the images, reducing the time it takes to show them. also, it would let you control exactly how you wish to show them on other densities, so no scaling artefacts would be shown. you don't have to put those files, but if you do, don't forget to change their sizes accordingly (for example 100x100 image on xhdpi should be 50x50 on mdpi). putting those images on the different folders are important for the app icon and other icons. not quite needed for high resolutions images. – android developer Sep 01 '13 at 05:20
  • Damn. Its works perfect with nexus 4. but hangs and shows the same error " Out Of Memory" when i test it on xperia L. – Abhijit Sep 01 '13 at 06:10
  • what is the density on this device, and what is the resolution of each image? as i've written, you should consider downscaling the images to the size you need to show them. you can look at the post i've written about how to do it. – android developer Sep 01 '13 at 07:15
  • Got the solution. I just had to store the app on sd card, to save the memory. and it works now – Abhijit Sep 02 '13 at 04:29
  • @Abhijit saving an app to the sd card doesn't affect the RAM memory. it only saves on internal storage . if your device runs a 3.0 android version and above, you can get the state of how much memory is used in the DDMS tool , but looking at the "heap" tab. just select your app's process and click the green cylinder icon. – android developer Sep 02 '13 at 05:29
  • Thanks a ton for all your advise. Appreciate it – Abhijit Sep 02 '13 at 13:11
  • you should check out google IO lectures. they helped me a lot. – android developer Sep 02 '13 at 13:28