Glide: Clear memory cache when full allocated

Created on 18 Apr 2016  路  13Comments  路  Source: bumptech/glide

I have a problem when load image from url: OutofMemoryError.
it happened when I was allocated the full. How to know when allocated (memory cache) full and then clear memory cache?

Sorry my english's not good if you don't understand please ask me.

question

Most helpful comment

Glide should clear when the system needs memory.

This may have been wrong. It is only true if your Glide.with() usage gets a FragmentActivity or a Fragment. Even if you're only using application context for every with() call, it's possible to free up memory:

public class App extends Application {
    @Override public void onLowMemory() {
        super.onLowMemory();
        Glide.get(this).clearMemory();
    }
    @Override public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        Glide.get(this).trimMemory(level);
    }
}

All 13 comments

Glide should clear when the system needs memory. How do you use Glide? (What do you pass into with()?)

I use Glide to load image from listview in ActivityA. Then when click into item of listview, I startActivity detail B to display this image. When I loadmore a lot of items of listview (80 items) and view detail image many times, my memory ascending until Outofmemory.

I use with:

public static void loadImage(Context context, String url, ImageView imageView) {
        Glide.with(context)
                .load(url)
                .skipMemoryCache(true)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .placeholder(R.drawable.image_bg2)
                .centerCrop()
                .crossFade()
                .into(imageView);
    }

You probably have a leak somewhere.
What is context? How do you call this from list and detail? How does your adapter look like?

In DetailFragment I call with: ImageUtils.loadImage(getContext(), image.getUrl(), imageView);

In Fragment Listview I call from adapter with: ImageUtils.loadImage(MyApplication.getInstance().getApplicationContext(), image.getUrl(), holder.imageView);

don't use Application context if you are not download only.

So, in Adapter listview don't use MyApplication.getInstance().getApplicationContext() ?
Can I replace it by getContext()?

See http://stackoverflow.com/a/32887693/253468, just added some code to it, try to adapt that.

thank you very much. When I try your solution I still got outofmemory, when it has more than items.

Do you mean when you opened many details or when you scrolled a lot of items?

Thanks with your time.
I tried to test the following:

Open Fragment listView then:

  • I click to view Detail Fragment then press back button to back to fragment listview.
  • Try again with just item 1 many times.

I see that:

  1. I open listview, my allowcated is 13.76mb.
  2. I click to the item to view detail, my allowcated is 15.74mb.
  3. I click back button to back listview fragment, my allocated is 17.5mb.

I repeat second and third step. Each time repeating my allocated increased more than.

I don't know why?

This is short my code:

Fragment ListView:

...
private MyListAdapter adapter;
...
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_list, container, false);
    initView(view);
    getData();
    ...
    return view;
}

private void initView(View view) {
    RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list_recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    if (adapter == null) {
        adapter = new MyListAdapter(Glide.with(this), this);
    }
    recyclerView.setAdapter(adapter);
    ...
}

private void getData() {
    ...
    List<ImageItem> list = ...;
    adapter.refreshData(list);
    ...
}

@Override
public void onClickItem(ImageItem item) {
    Fragment fragment = new DetailFragment();
    Bundle data = new Bundle();
    data.putSerializable(ConstantFields.KEY_SELECTED, item);
    fragment.setArguments(data);

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
    fragmentTransaction.replace(R.id.container_frame, fragment);
    fragmentTransaction.addToBackStack(TAG);
    fragmentTransaction.commit();
}

...

Adapter:

...
private List<ImageItem> items;
...
private final RequestManager requestManager;

public MyListAdapter(RequestManager requestManager, MyListener _listener) {
    this.listener = _listener;
    this.requestManager = requestManager;
}

public void refreshData(List<ImageItem> data) {
    this.items = data;
    notifyDataSetChanged(); 
}
...
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    ...
    ImageUtils.loadImage(requestManager, url, holder.imageView);
    ...
}
...

Detail Fragment:

...
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_detail, container, false);
    ...
    initView(view);
    return view;
}

private void initView(View view) {
    ...
    ImageUtils.loadImage(Glide.with(this), url, imageView);
    ...
}

private void backPressButton() {
    getFragmentManager().popBackStack(BooksFragment.TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
...

LoadImage:

public static void loadImage(RequestManager request, String url, ImageView imageView) {
    request.load(url)
        .skipMemoryCache(true)
        .diskCacheStrategy(DiskCacheStrategy.ALL)
        .placeholder(R.drawable.image_bg2)
        .centerCrop()
        .crossFade()
        .into(imageView);
}

I didn't see anything obviously wrong here, tried twice. Try the following:
Repeat steps 2-3 as many times as you can, but stop right before the app would crash. You can do this by reproducing once and counting how many times it was possible, e.g. N, then next time repeat N-1 times so it barely doesn't crash.
Then go to Android Monitor in AS/IDEA and Memory tab inside that; do a GC a few times and then take a heap dump. Go to captures/x.hprof and use p:\tools\sdk\android\platform-tools\hprof-conv.exe to convert this file into a Generic heap dump. Use Eclipse MAT to find a GC root for the large objects that you find. You may have to do some research on some steps here, but it will worth your time.

thanks for your help. I will test again

Glide should clear when the system needs memory.

This may have been wrong. It is only true if your Glide.with() usage gets a FragmentActivity or a Fragment. Even if you're only using application context for every with() call, it's possible to free up memory:

public class App extends Application {
    @Override public void onLowMemory() {
        super.onLowMemory();
        Glide.get(this).clearMemory();
    }
    @Override public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        Glide.get(this).trimMemory(level);
    }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

PatrickMA picture PatrickMA  路  3Comments

FooBarBacon picture FooBarBacon  路  3Comments

billy2271 picture billy2271  路  3Comments

piedpiperlol picture piedpiperlol  路  3Comments

ghost picture ghost  路  3Comments