简体   繁体   中英

Scrolling GridView causes GC_FOR_ALLOC free issues

I have a gridview with some images inside. Sometime when I'm scrolling, GC_FOR_ALLOC or heap is increased and I don't know why. I used a method to load a minimized image.

Might I use Picasso or a ViewHolder ? RecyclerView ?

The memory issues happened once or twice when I tested my app on my personal device although everything still ran. But on an older smartphone ( less efficient) , the memory issues totally stopped the phone and other apps from running.

I see warnings on my "setTag" as though the problem is caused by a memory leak.

How can I repair the memory problems ?

MainActivity.java

public class MainActivity extends Activity {
GridView gridView;
MediaPlayer mPlayer;

@Override
public synchronized void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    boolean internetAcces = checkDataConnection();
    if(internetAcces == true){
        setContentView(R.layout.activity_main);
        AdView adView = (AdView) this.findViewById(R.id.adView);
        AdRequest adRequest1 = new AdRequest.Builder().build();
        adView.loadAd(adRequest1);
    }
    else{
        setContentView(R.layout.activity_main2);
    }
    gridView = (GridView)findViewById(R.id.gridview);
    gridView.setAdapter(new MyAdapter(this));
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() 
    {
            @Override
            public synchronized void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {

                try{
                    if(mPlayer != null && mPlayer.isPlaying())
                    {
                        mPlayer.stop();
                        mPlayer.release();
                        playSong(position);
                    }
                    else
                    {
                        playSong(position);
                    }
                }catch(Exception ex){
                    //Toast.makeText(MainActivity.this, ex.getMessage(), Toast.LENGTH_SHORT).show();
                }

            }
    });


}

@Override
protected void onPause(){
    super.onPause();
}

@Override
protected void onStop() {
    super.onStop();
    System.exit(0);
}

@Override
protected void onDestroy(){
    super.onDestroy();
    System.exit(0);
}

Here's MyAdapter.java

public final class MyAdapter extends BaseAdapter {
private final List<Item> mItems = new ArrayList<Item>(30);
private final LayoutInflater mInflater;
public Context context;

public MyAdapter(Context context) {
    mInflater = LayoutInflater.from(context);
    this.context = context;

    mItems.add(new Item("Hé pélo",       R.drawable.hepelo));
    mItems.add(new Item("Salut les losers",   R.drawable.salutleslosers));
    mItems.add(new Item("Arrête Abib", R.drawable.abib));
    mItems.add(new Item("Goût bite",      R.drawable.goutbite));
    mItems.add(new Item("Makassy",     R.drawable.makassy));
    mItems.add(new Item("Joris Lecon",      R.drawable.jorislecon));
    mItems.add(new Item("Cache la drogue",       R.drawable.cacheladrogue));
    mItems.add(new Item("Un peu trop tactile",   R.drawable.unpeutroptactile));
    mItems.add(new Item("Qui c'est qu'a touché à Dorian ?", R.drawable.dorian));
    mItems.add(new Item("T'es pas beau",      R.drawable.tespasbeau));
    mItems.add(new Item("Ta mère",     R.drawable.tamere));
    mItems.add(new Item("Je bute ce paquet de chips",     R.drawable.jebutecepaquetdechips));
    mItems.add(new Item("La maison du content",     R.drawable.lamaisonducontent));
    mItems.add(new Item("Mes péripétiiiiiies",     R.drawable.mesperipeties));
    mItems.add(new Item("La rapta babtou",     R.drawable.laraptababtou));
    mItems.add(new Item("Que vas-tu faire ?!",     R.drawable.bangbang));
    mItems.add(new Item("Oh les tétés !",     R.drawable.lestetes));
    mItems.add(new Item("Mollé mollé",     R.drawable.laraptababtou));
    mItems.add(new Item("Okéééé",     R.drawable.ok));
    mItems.add(new Item("Guillaume le thug",     R.drawable.guillaumelethug));
    mItems.add(new Item("C'est ma teub",     R.drawable.cestmateub));
    mItems.add(new Item("Je suis qu'un thug",     R.drawable.jsuisquunthug));
}

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

@Override
public Item getItem(int i) {
    return mItems.get(i);
}

@Override
public long getItemId(int i) {
    return mItems.get(i).drawableId;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
    View v = view;
    ImageView picture;
    TextView name;

    if (v == null) {
        v = mInflater.inflate(R.layout.grid_item, viewGroup, false);
        v.setTag(R.id.picture, v.findViewById(R.id.picture));
        v.setTag(R.id.text, v.findViewById(R.id.text));
    }

    picture = (ImageView) v.getTag(R.id.picture);

    name = (TextView) v.getTag(R.id.text);

    Item item = getItem(i);

    //picture.setImageResource(item.drawableId);
    picture.setImageBitmap(decodeSampledBitmapFromResource(context.getResources(),item.drawableId, 150, 150));

    name.setText(item.name);

    return v;}




public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

    final int halfHeight = height / 2;
    final int halfWidth = width / 2;

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
    // height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;}


public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

private static class Item {
    public final String name;
    public final int drawableId;

    Item(String name, int drawableId) {
        this.name = name;
        this.drawableId = drawableId;
    }
}

}

main_activity.xml :

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<GridView
    android:id="@+id/gridview"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_gravity="center"
    android:verticalSpacing="0dp"
    android:layout_weight="1"
    android:horizontalSpacing="0dp"
    android:stretchMode="columnWidth"
    android:numColumns="2"
    android:listSelector="@android:color/transparent"
    android:scrollingCache="false"
    android:animationCache="false"
 />

  <com.google.android.gms.ads.AdView
    android:id="@+id/adView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    ads:adSize="SMART_BANNER"
    ads:adUnitId="ca-app-pub-2373549811754777/2717783647" 
   />

grid_item.xml :

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
<com.slamingresources.laboiteamisterv.SquareImageView
    android:id="@+id/picture"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    />

<TextView
    android:id="@+id/text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="4dp"
    android:paddingBottom="5dp"
    android:layout_gravity="bottom"
    android:textColor="@android:color/white"
    android:background="#55000002"
    />

Logcat :

11-20 03:21:45.878: I/dalvikvm-heap(16815): Clamp target GC heap from      128.451MB to 128.000MB
11-20 03:21:47.628: I/dalvikvm-heap(16815): Clamp target GC heap from 135.930MB to 128.000MB
11-20 03:21:47.688: D/dalvikvm(16815): GC_BEFORE_OOM freed 109065K, 85% free 20521K/131004K, paused 59ms, total 60ms
11-20 03:22:00.498: D/dalvikvm(16815): GC_FOR_ALLOC freed 3972K, 85% free 20494K/131004K, paused 24ms, total 24ms

I know this is old but for those that are still looking for same answers: you can use getcachedir() to store data temporarily in Android.

For more options see Android data storage .

Yes, you got this error! Why? AFAIK, before Android 3.0 (I dont remember exactly) bitmap is not auto recycle . You must recycle bitmap after not using it. To resolve your problem, I suggest you cache your Bitmap . When cached hit, recycle unused one.
: I think the easiest way to solve your problem is use another library to help loading image. :我认为解决您的问题的最简单方法是使用另一个库来帮助加载图像。 You can look at Universal ImageLoader . There's a function which can help you load with target size:

// Load image, decode it to Bitmap and return Bitmap synchronously
ImageSize targetSize = new ImageSize(80, 50); // result Bitmap will be fit to this size
Bitmap bmp = imageLoader.loadImageSync(imageUri, targetSize, options);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM