0

I am Using this Fragment in which Song title,Artist Name, and Album art for corresponding song is being displayed in the custom ListView.

I am getting smooth Scrolling with the code. But the problem is that memory consumption for the app containing only one Activity and Fragment is very high. Can you suggest alternative approach. or help me increase efficiency of this code. thanks.

package com.vamp.playerFragments;

import android.content.ContentUris;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import com.vamp.R;
import com.vamp.adapters.AllSongsAdapter;
import com.vamp.models.AllSongsModel;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class AllSongs extends Fragment {
public AllSongsAdapter adapter;
private ListView allSongsList;
private int[] albumArts;
private String[] allSongs;
private String[] artistName;
private ArrayList<AllSongsModel> rowItems;
private OnFragmentInteractionListener mListener;

public AllSongs() {
    // Required empty public constructor
}
public static AllSongs newInstance(String param1, String param2) {
    AllSongs fragment = new AllSongs();
    Bundle args = new Bundle();
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_all_songs, container, false);
    allSongsList = (ListView) rootView.findViewById(R.id.allSongsList);
    rowItems = new ArrayList<AllSongsModel>();
    init_Songs_list();
    adapter = new AllSongsAdapter(getActivity(), rowItems);
    allSongsList.setAdapter(adapter);
    return rootView;
}

public void init_Songs_list() {
    Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    String proj[] = {
            MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM_ID
    };

    Cursor MainCursor = getActivity().getContentResolver().query(uri, proj, MediaStore.Audio.Media.IS_MUSIC + " =1", null, MediaStore.Audio.Media.TITLE + " ASC");
    MainCursor.moveToFirst();
    while (MainCursor.moveToNext()) {

        String title = MainCursor.getString(MainCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
        String artistName = MainCursor.getString(MainCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
        Long albumId = MainCursor.getLong(MainCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
        Uri sArtWorkUri = Uri.parse("content://media/external/audio/albumart");
        Uri albumArtUri = ContentUris.withAppendedId(sArtWorkUri, albumId);

        Bitmap bitmap = null;
        try {
            bitmap = MediaStore.Images.Media.getBitmap(
                    getActivity().getContentResolver(), albumArtUri);
            //bitmap = Bitmap.createScaledBitmap(bitmap, 30, 30, true);

        } catch (FileNotFoundException exception) {
            exception.printStackTrace();
            bitmap = BitmapFactory.decodeResource(getActivity().getResources(),
                    R.drawable.ic_launcher);
        } catch (IOException e) {

            e.printStackTrace();
        }
        AllSongsModel allSongsModel = new AllSongsModel();
        allSongsModel.setSongName(title);
        allSongsModel.setArtistName(artistName);
        allSongsModel.setAlbumArt(bitmap);
        rowItems.add(allSongsModel);
    }

}

}
Prashant18
  • 11
  • 5
  • possible duplicate of [Strange out of memory issue while loading an image to a Bitmap object](http://stackoverflow.com/questions/477572/strange-out-of-memory-issue-while-loading-an-image-to-a-bitmap-object) – Simon Jan 09 '15 at 17:36
  • Do you know the resolution of the bitmaps you are trying to display? – Jack Jan 09 '15 at 17:37
  • @Jack No they are album arts from the database MEDIASTORE so I don't know the resolution. I am getting smooth scrolling.and app is working fine but I think it is taking more memory then It should be. I tried google's approach http://developer.android.com/training/displaying-bitmaps/load-bitmap.html but getting almost same results. – Prashant18 Jan 09 '15 at 17:42
  • Resize all of the bitmaps before you load them. – Jack Jan 09 '15 at 17:53

3 Answers3

0

I don't know if you like using third-party libraries, but I use this one in my project and it's optimized to this situations (and plenty others). Check Picasso, give it a try ! It's pretty easy to use and their docs are excellent.

Hope it helps!

Leonardo
  • 3,141
  • 3
  • 31
  • 60
  • Thank you @Leonardo Ferrari I am defiantly going to try this lib and tell you how it works. – Prashant18 Jan 09 '15 at 17:48
  • 1
    this should probably be a comment since all you do is refer the OP to a library and dont directly answer the question – tyczj Jan 09 '15 at 17:50
  • I don't think so, if he switches to Picasso probably this problem will vanish, thus answering his question. – Leonardo Jan 09 '15 at 17:52
  • He's storing all the bitmaps in his adapter now. Picasso would provide disk caching, which would solve his memory issue. – dangVarmit Jan 09 '15 at 18:09
  • Actually Picasso doesn't provide disk cache, only in-memory. Anyway, the memory issue will go away. – Leonardo Jan 09 '15 at 23:05
  • @LeonardoFerrari I can't get picasso work with offline database so. I tried different approch with different library. Thanks for support though – Prashant18 Jan 12 '15 at 10:54
0

You should resize your bitmaps before you load them using the following code:

Bitmap downsizeBitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, false);

This will dramatically reduce memory consumption if your bitmaps are a lot bigger.

Jack
  • 2,043
  • 7
  • 40
  • 69
0

After Searching and implementing lots of method I came to find this awesome library. https://github.com/nostra13/Android-Universal-Image-Loader and implemented as per the instructions and Now the app is working fine. With no more memory issues and almost same performance as before. Check out the code below.

package com.vamp.adapters;
import...//all the imports/

public class AllSongsAdapter extends BaseAdapter {
private ArrayList<AllSongsModel> mAllSongsList;
private Context context;
private LayoutInflater mInflater;
private AllSongsModel allSongsModel;
private Bitmap bmp;
public AllSongs allSongs;

//Android Universal Image Loader Classes.
private DisplayImageOptions options;
private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();

public AllSongsAdapter(Context context, ArrayList<AllSongsModel> mAllSongsList) {
    mInflater = LayoutInflater.from(context);
    this.mAllSongsList = mAllSongsList;
    this.context = context;


    options = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.ic_launcher)
            .showImageForEmptyUri(R.drawable.ic_launcher)
            .showImageOnFail(R.drawable.ic_launcher)
            .cacheInMemory(true)
            .cacheOnDisk(true)
            .considerExifParams(true)
            .displayer(new RoundedBitmapDisplayer(20))
            .build();
}

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

@Override
public Object getItem(int position) {
    return mAllSongsList.get(position);
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    View view;
    ViewHolder holder;
    if (convertView == null) {
        view = mInflater.inflate(R.layout.all_songs_list_row, parent, false);
        holder = new ViewHolder();
        holder.albumArt = (ImageView) view.findViewById(R.id.all_songs_list_row_albumart);
        holder.songName = (TextView) view.findViewById(R.id.all_songs_list_row_songName);
        holder.artistName = (TextView) view.findViewById(R.id.all_songs_list_row_artistName);
        view.setTag(holder);
    } else {
        view = convertView;
        holder = (ViewHolder) view.getTag();
        //holder.mImageLoader.cancel();
    }


    AllSongsModel allSongsModel = mAllSongsList.get(position);
   ImageLoader.getInstance().displayImage(Uri.decode(String.valueOf(allSongsModel.getAlbum_art_uri())),holder.albumArt,options,animateFirstListener);
    holder.songName.setText(allSongsModel.getSongName());
    holder.artistName.setText(allSongsModel.getArtistName());
    return view;
}

private class ViewHolder {
    public ImageView albumArt;
    public TextView songName, artistName;
    public AsyncImageSetter mImageLoader;
}

private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {

    static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());

    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        if (loadedImage != null) {
            ImageView imageView = (ImageView) view;
            boolean firstDisplay = !displayedImages.contains(imageUri);
            if (firstDisplay) {
                FadeInBitmapDisplayer.animate(imageView, 500);
                displayedImages.add(imageUri);
            }
        }
    }
}
}

And My AllSongs.java(Fragment) class is same as before with only One change that Instead of using Bitmap Directly to the adapter I am now passing the URI of that Bitmap to the adpater.And the app just works flawlessly.

Thanks to everyone who suggested me different approaches for the solution. I learned a lot from this.

Prashant18
  • 11
  • 5