ViewPager memory leak - android

I am having a ViewPager which works well, but having a memory leak in it.
I tried to find the leak with the heap analysis and with Eclipse memory analyser.
It turns out I got several ViewPager instances and not released Bitmaps in the heap after several activity recreations.
Where can be the leak reason in my code?
Here is the Fragment, in which I use ViewPager and scroll items after some period of time:
private final int INTERVAL_TIME = 15000;
private ViewPager mViewPager;
private ViewPagerAdapter mAdapter;
private Handler mHandler;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_bottom, container, false);
......
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mAdapter = new ViewPagerAdapter(getActivity(), bottomItems);
mViewPager.setAdapter(mAdapter);
mHandler = new Handler();
mHandler.postDelayed(UpdateTimeThread, INTERVAL_TIME);
return view;
}
private Runnable UpdateTimeThread = new Runnable() {
#Override
public void run() {
int position;
if (mViewPager.getCurrentItem() == mViewPager.getAdapter().getCount() - 1) {
position = 0;
} else {
position = mViewPager.getCurrentItem() + 1;
}
mViewPager.setCurrentItem(position, true);
mHandler.postDelayed(this, INTERVAL_TIME);
}
};
And here is my PagerAdapter which can show simultaneously 3 items on the screen (if their format.equals("1")) or 2 items at a time in case one of them is double sized (format.equals("2"))
public class ViewPagerAdapter extends PagerAdapter {
private final List<JsonParsed.BottomItem> bottomItems;
private Activity activity;
public ViewPagerAdapter(Activity activity, List<JsonParsed.BottomItem> bottomItems) {
this.activity = activity;
this.bottomItems = bottomItems;
}
#Override
public int getCount() {
if (bottomItems.size() < 3) {
return 1;
}
return (int) Math.floor((float) bottomItems.size() / 3f);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.pager_item, container, false);
ImageView pic = (ImageView) itemView.findViewById(R.id.image_item);
ImageView pic2 = (ImageView) itemView.findViewById(R.id.image_item2);
ImageView pic3 = (ImageView) itemView.findViewById(R.id.image_item3);
pic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
click(bottomItems.get(position * 3));
}
});
pic2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
click(bottomItems.get(position * 3 + 1));
}
});
pic3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
click(bottomItems.get(position * 3 + 2));
}
});
if (bottomItems.get(position * 3) != null) {
pic.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3).getPrev(activity).getAbsolutePath()));
if (bottomItems.get(position * 3).format.equals("1")) {
pic.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
} else if (bottomItems.get(position * 3).format.equals("2")) {
pic.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
}
} else {
pic.setVisibility(View.GONE);
}
if (bottomItems.size() > position * 3 + 1 && bottomItems.get(position * 3 + 1) != null) {
pic2.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3 + 1).getPrev(activity).getAbsolutePath()));
if (bottomItems.get(position * 3 + 1).format.equals("1")) {
pic2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
} else if (bottomItems.get(position * 3 + 1).format.equals("2")) {
pic2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
}
} else {
pic2.setVisibility(View.GONE);
}
if (bottomItems.size() > position * 3 + 2 && bottomItems.get(position * 3 + 2) != null) {
pic3.setImageBitmap(BitmapFactory.decodeFile(bottomItems.get(position * 3 + 2).getPrev(activity).getAbsolutePath()));
if (bottomItems.get(position * 3 + 2).format.equals("1")) {
pic3.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 2f));
} else if (bottomItems.get(position * 3 + 2).format.equals("2")) {
pic3.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
}
} else {
pic3.setVisibility(View.GONE);
}
container.addView(itemView);
return itemView;
}
private void click(JsonParsed.BottomItem bottomItem) {
if (bottomItem.url != null && !bottomItem.url.isEmpty()) {
((MainActivity) activity).showWebView(bottomItem.url);
} else if (bottomItem.video != null && !bottomItem.video.isEmpty()) {
((MainActivity) activity).onPlayMedia(bottomItem.getVideo(activity).getAbsolutePath(), bottomItem.id, false);
}
}
#Override
public void destroyItem(ViewGroup container, int position, Object view) {
container.removeView((LinearLayout) view);
}
Many thanks for any piece of advice
EDIT:
Finally solved the leak.
As Egor pointed out, the main leak has been caused by the Handler,
as it kept the reference onto ViewPager instance so instances were not garbage collected.
Finally I just used lazy solution - WeakHandler (open source library).
I guess it does the same, as described in Egors's article,
but it's pretty handy to use it, as you just using it as usual Handler:
WeakHandler().postDelayed(....) and thats it.
Also I used week references for the Bitmaps and all memory leaks disappeared

Most likely the Handler is the one causing your memory leaks. There's a wonderful article which describes this problem in detail, suggesting that you use a WeakReference to solve the problem.

Related

Android Card view random text comes in the view from other card values

In Android card view when I open the category page first, it is all good, but when I scroll to bottom and again scroll to top the values from other cards come to the hidden values of some above cards. Need Help..
Folowing is the fragment file of the product list
Fragment File:
public class ProductsList extends Fragment {
View view;
#BindView(R.id.categoryRecyclerView)
RecyclerView productsRecyclerView;
public static int categoryPosition;
#BindView(R.id.noProductAddedLayout)
LinearLayout noProductAddedLayout;
#BindView(R.id.contShopping)
Button contShopping;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view = inflater.inflate(R.layout.fragment_category_list, container, false);
ButterKnife.bind(this, view);
MainActivity.title.setText(SplashScreen.categoryListResponseData.get(categoryPosition).getCategory_name());
setProductsData();
contShopping.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
((MainActivity) getActivity()).removeCurrentFragmentAndMoveBack();
}
});
return view;
}
#Override
public void onStart() {
super.onStart();
((MainActivity) getActivity()).lockUnlockDrawer(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
MainActivity.search.setVisibility(View.VISIBLE);
Config.getCartList(getActivity(), true);
}
#Override
public void onDestroyView() {
super.onDestroyView();
MainActivity.search.setVisibility(View.GONE);
}
private void setProductsData() {
if (SplashScreen.categoryListResponseData.get(categoryPosition).getProducts().size() > 0) {
ProductListAdapter productListAdapter;
GridLayoutManager gridLayoutManager;
gridLayoutManager = new GridLayoutManager(getActivity(), 2);
productsRecyclerView.setLayoutManager(gridLayoutManager);
productListAdapter = new ProductListAdapter(getActivity(), SplashScreen.categoryListResponseData.get(categoryPosition).getProducts(), categoryPosition);
productsRecyclerView.setAdapter(productListAdapter);
} else {
noProductAddedLayout.setVisibility(View.VISIBLE);
}
}
}
Adapter file:
public class ProductListAdapter extends RecyclerView.Adapter<HomeProductsViewHolder> {
Context context;
List<Product> productList;
int categoryPosition;
String mrp;
String sellPrice;
public ProductListAdapter(Context context, List<Product> productList, int categoryPosition) {
this.context = context;
this.productList = productList;
this.categoryPosition = categoryPosition;
}
#Override
public HomeProductsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.home_products_list_items, null);
HomeProductsViewHolder homeProductsViewHolder = new HomeProductsViewHolder(context, view, productList);
return homeProductsViewHolder;
}
#Override
public void onBindViewHolder(final HomeProductsViewHolder holder, final int position) {
holder.cardView.setVisibility(View.VISIBLE);
holder.cardView1.setVisibility(View.GONE);
holder.productName.setText(productList.get(position).getProductName());
holder.price.setText(MainActivity.currency + " " + productList.get(position).getSellprice());
try {
Picasso.with(context)
.load(productList.get(position).getImages().get(0))
.resize(Integer.parseInt(context.getResources().getString(R.string.targetProductImageWidth)), Integer.parseInt(context.getResources().getString(R.string.targetProductImageHeight)))
.placeholder(R.drawable.defaultimage)
.into(holder.image);
} catch (Exception e) {
}
try {
double discountPercentage = Integer.parseInt(productList.get(position).getMrpprice()) - Integer.parseInt(productList.get(position).getSellprice());
Log.d("percentage", discountPercentage + "");
discountPercentage = (discountPercentage / Integer.parseInt(productList.get(position).getMrpprice())) * 100;
if ((int) Math.round(discountPercentage) > 0) {
holder.discountPercentage.setText(((int) Math.round(discountPercentage) + "% Off"));
} else {
holder.discountPercentage.setText("");
}
mrp = productList.get(position).getMrpprice();
sellPrice = productList.get(position).getSellprice();
Log.i("MRP PRICE------>>>>", mrp +" a");
Log.i("Sell Price PRICE->>", sellPrice +" b");
holder.actualPrice.setText(MainActivity.currency + " " + productList.get(position).getMrpprice());
holder.actualPrice.setPaintFlags(holder.actualPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} catch (Exception e) {
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ProductDetail.productList.clear();
ProductDetail.productList.addAll(productList);
ProductDetail productDetail = new ProductDetail();
Bundle bundle = new Bundle();
bundle.putInt("position", position);
productDetail.setArguments(bundle);
((MainActivity) context).loadFragment(productDetail, true);
}
});
}
#Override
public int getItemCount() {
return productList.size();
}
}
RecyclerView is called like that because its Views are reused when you scroll. Because of that, you always have to set all attributes to all the Views in each grid cell. For example you have to assign an empty String ("") as text to holder.discountPercentage if the percentage value is <= 0.
Another thing: you need the try-catch block because you want to calculate the value for the double discountPercentage. After this value is known, you can proceed outside of the try-catch block.
double discountPercentage = 0;
try {
double discountPercentage = Integer.parseInt(productList.get(position).getMrpprice()) - Integer.parseInt(productList.get(position).getSellprice());
Log.d("percentage", discountPercentage + "");
discountPercentage = (discountPercentage / Integer.parseInt(productList.get(position).getMrpprice())) * 100;
}
catch (Exception e) {
// Log exception here
}
finally{
// either you managed to calculate a value for discountPercentage
// or it is still zero
// Anyway, you can set the text for the TextView now:
if ((int) Math.round(discountPercentage) > 0) {
holder.discountPercentage.setText(((int) Math.round(discountPercentage) + "% Off"));
}
// Note: there always has to be an "else" block,
// or the recycled View will keep the content from
// the previous call to onBindViewHolder()
else {
holder.discountPercentage.setText("");
}
}
// as far as I can see, the TextView for the actual price
// does not depend on the discountPercentage
// so it can stay outside of the try-catch block
holder.actualPrice.setText(MainActivity.currency + " " + productList.get(position).getMrpprice());
holder.actualPrice.setPaintFlags(holder.actualPrice.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);

How to solve recyclerv view list update delay

There is a delay in updating the list of Recycler views. When items in the list are small, they are processed quickly, but when items are large, delays occur. The model of all items is the same, but it does not seem to be possible to use methods like NotifyItemChanged because it expresses different information and number.
#Override
public void onFolderCoverImgClick(int position) {
setVideoTopBarByFolderData(position);
AppVideoData.FolderData folderData = videoLayoutFolderList.get(position);
String folderId = folderData.getFolderId();
videoByFolderList.clear();
for (int i = 0; i < videoLayoutList.size(); i++) {
if (folderId.equals(videoLayoutList.get(i).getFolderId())) {
videoByFolderList.add(videoLayoutList.get(i));
}
}
String path = getFilesDir() + File.separator + "vid";
for (int i = 0; i < videoByFolderList.size(); i++) {
if (new File(path + File.separator + videoByFolderList.get(i).getId() + ".mp4").exists()) {
videoByFolderList.get(i).setVideoType("Download");
} else {
videoByFolderList.get(i).setVideoType("vimeo");
}
if(videoIdF.equals(videoByFolderList.get(i).getId())) {
videoPosF = i;
}
}
videoPortraitAdapter.updateList(videoByFolderList);
videoPortraitAdapter.checkSelectedVideoWhenFolder(videoPosF, videoIdF);
}
If I click on a specific view, it will be called back to the above method, and clear the list that was originally in the recycler view and update the new list to be shown. The rest of the code is responsible for additional processing. I tried to calculate the time using the 'System.currentTimeMillis' method, but it does not seem to cause delays in additional code.
public class VideoItemAdapter extends RecyclerView.Adapter<VideoItemAdapter.VideoViewHolder> {
public VideoItemAdapterListener videoItemAdapterListener;
public VideoItemDrawDoneListener videoItemDrawDoneListener;
private Context context;
private LiveActivity liveActivity;
private List<AppVideoData.AppYouTube> dataList;
private String skinColor;
private boolean fullScreen;
private boolean isFolder;
private int videoPosF;
private String videoIdF;
public VideoItemAdapter(Context context, List<AppVideoData.AppYouTube> dataList, String skinColor, boolean fullScreen, boolean isFolder) {
this.context = context;
this.dataList = dataList;
this.skinColor = skinColor;
this.fullScreen = fullScreen;
if (context instanceof LiveActivity) {
liveActivity = (LiveActivity) context;
}
this.isFolder = isFolder;
}
public void updateList(List<AppVideoData.AppYouTube> dataList) {
this.dataList = dataList;
notifyDataSetChanged();
}
public void setOnVideoItemClickListener(VideoItemAdapterListener videoItemAdapterListener) {
this.videoItemAdapterListener = videoItemAdapterListener;
}
public void setOnVideoItemDrawDoneListener(VideoItemDrawDoneListener videoItemDrawDoneListener) {
this.videoItemDrawDoneListener = videoItemDrawDoneListener;
}
#NonNull
#Override
public VideoItemAdapter.VideoViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.video_item, parent, false);
VideoViewHolder holder = new VideoViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull final VideoItemAdapter.VideoViewHolder holder, final int position) {
Log.d("time", "onBindViewHolder: " + System.currentTimeMillis());
int adapterPosition = 0;
if(holder.getAdapterPosition() != RecyclerView.NO_POSITION) { adapterPosition = holder.getAdapterPosition(); }
AppVideoData.AppYouTube videoData = dataList.get(adapterPosition);
String videoType = videoData.getVideoType();
Glide.with(context).load(videoData.getVideoThumbnail()).into(holder.itemThumbnail);
holder.itemSelected.setImageResource(R.drawable.shining_selected);
holder.itemTitle.setText(videoData.getTitle());
holder.itemDivider.setBackgroundColor(Color.parseColor(skinColor));
holder.itemDuration.setText(getDuration(videoData.getDuration()));
changeVideo(holder, adapterPosition, videoData.getId());
if (!videoType.equals("Download")) {
holder.itemDownload.setVisibility(View.VISIBLE);
holder.itemDelete.setVisibility(View.INVISIBLE);
} else {
holder.itemDownload.setVisibility(View.INVISIBLE);
holder.itemDelete.setVisibility(View.VISIBLE);
}
if(fullScreen) {
holder.itemDownload.setVisibility(View.INVISIBLE);
holder.itemDelete.setVisibility(View.INVISIBLE);
}
Log.d("time", "onBindViewHolder1: " + System.currentTimeMillis());
}
#Override
public int getItemCount() {
return (dataList != null) ? dataList.size() : 0;
}
private String getDuration(int original) {
int hour = original / 60 / 60;
int min = (original - (hour * 60 * 60)) / 60;
int sec = original - (hour * 60 * 60) - (min * 60);
return (hour > 0) ? String.format("%02d:%02d:%02d", hour, min, sec) : String.format("%02d:%02d", min, sec);
}
public void checkSelectedVideoWhenFolder(int videoPosF, String videoIdF) {
this.videoPosF = videoPosF;
this.videoIdF = videoIdF;
notifyItemChanged(videoPosF);
}
private void changeVideo(VideoViewHolder holder, int position, String videoId) {
if (!liveActivity.isFolder) {
if ((liveActivity.videoPos == position)) {
holder.itemSelected.setVisibility(View.VISIBLE);
} else {
holder.itemSelected.setVisibility(View.INVISIBLE);
}
} else {
if ((videoPosF == position) && videoIdF.equals(videoId)) {
holder.itemSelected.setVisibility(View.VISIBLE);
} else {
holder.itemSelected.setVisibility(View.INVISIBLE);
}
}
}
public class VideoViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
protected RelativeLayout itemBody;
protected TextView itemTitle;
protected TextView itemDuration;
protected TextView itemDivider;
protected ImageView itemThumbnail;
protected ImageView itemSelected;
protected ImageButton itemDownload;
protected ImageButton itemDelete;
public VideoViewHolder(View itemView) {
super(itemView);
itemBody = (RelativeLayout) itemView.findViewById(R.id.video_item_body);
itemTitle = (TextView) itemView.findViewById(R.id.video_item_title);
itemDuration = (TextView) itemView.findViewById(R.id.video_item_duration);
itemDivider = (TextView) itemView.findViewById(R.id.video_item_divider);
itemThumbnail = (ImageView) itemView.findViewById(R.id.video_item_thumbnail);
itemSelected = (ImageView) itemView.findViewById(R.id.video_item_selected);
itemDownload = (ImageButton) itemView.findViewById(R.id.video_item_download);
itemDelete = (ImageButton) itemView.findViewById(R.id.video_item_delete);
itemBody.setOnClickListener(this);
itemDownload.setOnClickListener(this);
itemDelete.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.video_item_body:
videoItemAdapterListener.onVideoItemClick(getAdapterPosition(), fullScreen, itemSelected);
break;
case R.id.video_item_download:
videoItemAdapterListener.onVideoDownloadClick(getAdapterPosition(), fullScreen);
break;
case R.id.video_item_delete:
videoItemAdapterListener.onVideoDeleteClick(getAdapterPosition(), fullScreen);
break;
}
}
}
This is a recycler view adapter class. In the onBindViewHolder method of the adapter, even if I calculate the time using System.currentTimeMillis, I can not see anything that delay could happen. It took 0.005 to 0.01 seconds. There is a place of doubt, but I do not know exactly where to check it. It looks like there is a difference of about 0.6 seconds between 'onFolderCoverImgClick' and onBindViewHolder.
videoPortraitAdapter is an instance of VideoItemAdapter. If you know anyone, I would appreciate it if you could.
You can use new ListAdapter instead of RecyclerView.Adapter which provides the submitList() method which manages the differences in the lists and updates those only. Refer this link.
Better alternative option is by using setting up swipe to refresh and use
mSwipeRefreshLayout.setRefreshing(false); - in place where updating the adapter is done or NotifyItemChanged.
This has always worked for me, hope this helps you.

Android 5.1.1 Out of memory Fatal signal 11 error on swiping Viewpager Fragmet

In my android application I've developed a Viewpager Fragment and inside it, a Single Fragment both extend Fragment class. The application is working fine but after swiping 10-15 pages forward or backward, it randomly crashes with the following error in logcat:
12-20 22:50:21.367: W/ResourceType(21279): Failure getting entry for 0x01080af7 (t=7 e=2807) (error -75)
12-20 22:50:21.747: D/skia(21279): Skia Error: Out Of Memory: (size = 13833300)
12-20 22:50:21.747: A/libc(21279): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 21279 (s.iyykanastaeen)
The crash occurs only on samsung tablet 5.1.1 not on mobile phones.
EDIT The crash happens only when custom font is applied using typeface.
try{
font = Typeface.createFromAsset(tvDuaArabic.getContext().getAssets(), "fonts/arabtype.ttf");
ufont = Typeface.createFromAsset(tvDuaUrdu.getContext().getAssets(), "fonts/jameelnoorinastaleeq.ttf");
}
catch (Exception e)
{
e.printStackTrace();
// Prints what exception has been thrown
System.out.println(e);
}
tvDuaArabic.setTypeface(font);
Please help me fix this problem on tablet as well.
Here's the code from Viewpager fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
context = inflater.getContext();
rootView = (ViewGroup) inflater.inflate(R.layout.fragment_single_dua_view_pager, container, false);
ga= new GridViewAdapter(context);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
ll_back_single_dua_header = (LinearLayout) rootView.findViewById(R.id.ll_back_single_dua_header);
ll_back_single_dua_footer = (LinearLayout) rootView.findViewById(R.id.ll_back_single_dua_footer);
tv_back_single_dua_header_title = (TextView) rootView.findViewById(R.id.tv_back_single_dua_header_title);
ufont = Typeface.createFromAsset(getActivity().getAssets(), "fonts/jameelnoorinastaleeq.ttf");
tv_back_single_dua_footer_counter = (TextView) rootView.findViewById(R.id.tv_back_single_dua_footer_counter);
togbtnIsFavorite = (ToggleButton) rootView.findViewById(R.id.tog_btn_favorite_dua);
togbtnRepeat = (ToggleButton) rootView.findViewById(R.id.tog_btn_repeat_dua);
btnPlayPauseDua = (ImageButton) rootView.findViewById(R.id.btn_play_pause_dua);
btnShareDua = (ImageButton) rootView.findViewById(R.id.btn_share_dua);
btn_list_duas = (ImageButton) rootView.findViewById(R.id.btn_list_duas);
tv_back_single_dua_footer_counter.setText("1/1");
mPager = (ViewPager) rootView.findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
mPageNumber = position;
stopMusicPlayback();
updateView();
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
#Override
public void onPageScrollStateChanged(int arg0) {}
});
mPager.setAdapter(mPagerAdapter);
String verses = new SharedPreferencesSupplication().read(SingletonClass.keyListOfVerses, "a1");
String[] versesList = verses.split(",");
int total = versesList.length;
int position = new SharedPreferencesSupplication().read(SingletonClass.keySelVerseFromList, 0);
mPager.setCurrentItem((total - 1) - position);
updateView();
super.onActivityCreated(savedInstanceState);
}
#Override
public void onResume() {
// TODO Auto-generated method stub
repeatDua = false;
togbtnRepeat.setChecked(false);
updateView();
if (new SharedPreferencesSupplication().read(SingletonClass.keyPlayAll, false))
btnPlayPauseDua.performClick();
super.onResume();
}
void updateView() {
mPageNumber = mPager.getCurrentItem();
String verses = new SharedPreferencesSupplication().read(SingletonClass.keyListOfVerses, "a1");
String[] versesList = verses.split(",");
int index = (versesList.length - 1) - mPageNumber;
identifier = versesList[index];
int resID = getActivity().getResources().getIdentifier(identifier, "raw", getActivity().getPackageName());
try {
mp = MediaPlayer.create(context, resID);
}
catch (Exception e) {
mp = null;
}
btnPlayPauseDua.setBackgroundResource(R.drawable.play_btn_custom);
tv_back_single_dua_footer_counter.setText((index + 1) + " / " + versesList.length);
if (new FavoriteDuas().isDuaFavorite(identifier))
togbtnIsFavorite.setChecked(true);
else
togbtnIsFavorite.setChecked(false);
boolean lang= new SharedPreferencesSupplication().read(SingletonClass.keylang, false);
currPos = 0;
}
#Override
public void onPause() {
new SharedPreferencesSupplication().save(SingletonClass.keyPlayAll, false);
stopMusicPlayback();
super.onPause();
}
void stopMusicPlayback() {
if (mp instanceof MediaPlayer) {
mp.stop();
mp.release();
}
btnPlayPauseDua.setBackgroundResource(R.drawable.play_btn_custom);
}
private class ScreenSlidePagerAdapter extends FragmentPagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return (SingleDuaFragment.create(position));
}
#Override
public int getCount() {
// TODO Auto-generated method stub
String verses = new SharedPreferencesSupplication().read(SingletonClass.keyListOfVerses, "a1");
String[] versesList = verses.split(",");
return versesList.length;
}
}
And here's code from SingleFragment:
public static SingleDuaFragment create(int pageNumber) {
SingleDuaFragment fragment = new SingleDuaFragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, pageNumber);
fragment.setArguments(args);
return fragment;
}
public SingleDuaFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
context = inflater.getContext();
rootView = (ViewGroup) inflater.inflate(R.layout.fragment_single_dua, container, false);
tvDuaArabic = (TextView) rootView.findViewById(R.id.tv_arabic);
tvDuaEnglish = (TextView) rootView.findViewById(R.id.tv_english);
tvDuaUrdu = (TextView) rootView.findViewById(R.id.tv_urdu);
tvDuaTranslit = (TextView) rootView.findViewById(R.id.tv_transl);
tvDuaRef = (TextView) rootView.findViewById(R.id.tv_ref);
dividerEng = (TextView) rootView.findViewById(R.id.divider_english);
dividerUrdu = (TextView) rootView.findViewById(R.id.divider_urdu);
dividerTransl = (TextView) rootView.findViewById(R.id.divider_transl);
dividerRef = (TextView) rootView.findViewById(R.id.divider_ref);
return rootView;
}
#Override
public void onResume() {
// TODO Auto-generated method stub
boolean engTransVisible = new SharedPreferencesSupplication().read(SingletonClass.keyEngTrans, true);
boolean urdTransVisible = new SharedPreferencesSupplication().read(SingletonClass.keyUrdTrans, true);
String verses = new SharedPreferencesSupplication().read(SingletonClass.keyListOfVerses, "a1");
String[] versesList = verses.split(",");
int index = (versesList.length - 1) - mPageNumber;
String identifier = versesList[index];
Typeface font = Typeface.createFromAsset(tvDuaArabic.getContext().getAssets(), "fonts/arabtype.ttf");
//Typeface custom_font = Typeface.createFromAsset(tvDuaArabic.getContext().getAssets(), "fonts/Tahoma.ttf");
tvDuaArabic.setText(SingletonClass.duasAra.get(index));
//tvDuaArabic.setTypeface(custom_font);
tvDuaArabic.setTypeface(font);
tvDuaEnglish.setText(SingletonClass.duasEng.get(index));
Typeface ufont = Typeface.createFromAsset(tvDuaUrdu.getContext().getAssets(), "fonts/jameelnoorinastaleeq.ttf");
tvDuaUrdu.setText(SingletonClass.duasUrd.get(index));
tvDuaUrdu.setTypeface(ufont);
tvDuaTranslit.setText(SingletonClass.duasTransl.get(index));
if(engTransVisible)
tvDuaRef.setText(SingletonClass.duasRefEng.get(index));
else if (urdTransVisible)
tvDuaRef.setText(SingletonClass.duasRefUrd.get(index));
tvDuaRef.setTypeface(ufont);
}
int fontsize = FontSize.getFontSize();
//Typeface font = Typeface.createFromAsset(getActivity().getAssets(), "fonts/PDMS_Saleem_QuranFont-signed.ttf");
tvDuaArabic.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontsize*2 );
//tvDuaArabic.setTypeface(font);
tvDuaEnglish.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontsize);
tvDuaUrdu.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontsize);
tvDuaRef.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 0.75));
tvDuaTranslit.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 0.75));
dividerEng.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 2));
dividerUrdu.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 2));
dividerRef.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 2));
dividerTransl.setTextSize(TypedValue.COMPLEX_UNIT_SP, (float) (fontsize * 2));
boolean engTrans = new SharedPreferencesSupplication().read(SingletonClass.keyEngTrans, true);
boolean urduTrans = new SharedPreferencesSupplication().read(SingletonClass.keyUrdTrans, false);
boolean refVisible = new SharedPreferencesSupplication().read(SingletonClass.keyRef, false);
boolean transVisible = new SharedPreferencesSupplication().read(SingletonClass.keyTransl, false);
if (engTrans) {
tvDuaEnglish.setVisibility(View.VISIBLE);
dividerEng.setVisibility(View.VISIBLE);
}
else {
tvDuaEnglish.setVisibility(View.GONE);
dividerEng.setVisibility(View.GONE);
}
if (urduTrans) {
tvDuaUrdu.setVisibility(View.VISIBLE);
dividerUrdu.setVisibility(View.VISIBLE);
}
else {
tvDuaUrdu.setVisibility(View.GONE);
dividerUrdu.setVisibility(View.GONE);
}
if (refVisible) {
tvDuaRef.setVisibility(View.VISIBLE);
dividerRef.setVisibility(View.VISIBLE);
}
else {
tvDuaRef.setVisibility(View.GONE);
dividerRef.setVisibility(View.GONE);
}
if (transVisible) {
tvDuaTranslit.setVisibility(View.VISIBLE);
dividerTransl.setVisibility(View.VISIBLE);
}
else {
tvDuaTranslit.setVisibility(View.GONE);
dividerTransl.setVisibility(View.GONE);
}
if(!engTrans && !urduTrans){
if(SingletonClass.duasAra.get(index)==""){
tvDuaEnglish.setVisibility(View.VISIBLE);
dividerEng.setVisibility(View.VISIBLE);
//tvDuaEnglish.setText(SingletonClass.duasEng.get(index));
}
}
if(!engTrans && !urduTrans && !transVisible && refVisible){
tvDuaRef.setText(SingletonClass.duasRefEng.get(index));
}
svContent = (ScrollView) rootView.findViewById(R.id.sv_content);
svContent.scrollTo(0, 0);
super.onResume();
}
public int getPageNumber() {
return mPageNumber;
}
Thank you
I'm not sure, but does your adapter extend FragmentPagerAdapter? If so, try extending FragmentStatePagerAdapter instead. I also recommend LeakCanary and the Android Studio memory profiler to check if your fragments are leaking, or something in your fragments

Memory Leak due to PopupWindow

I have a FragmentA. When I click on a button in FragmentA I go to FragmentB. In FragmentB I have a PopupWindow. The PopupWindow have a ViewPager with two pages.
I took help from this code - Emojicon
I have 2 separate classes, View1 and View2, for the views at page 1 and 2 of the ViewPager respectively. Both these classes, View1 and View2, extends a parent class ViewBase.
Here is my problem:
Scenario 1: When I am at FragmentA the memory graph shows 13MB utilization. When I go to FragmentB without showing PopupWindow the memory graph shows 16MB and when I come back to FragmentA it comes down to 13MB. This is good.
Scenario 2: When I am at FragmentA the memory graph shows 13MB utilization. When I go to FragmentB with showing PopupWindow the memory graph shows 20MB and when I come back to FragmentA it doesn't come down to 13MB.
I have tried Eclipse MAT and Heap dump to find out the issue but still no help. I can see in the MAT that FragmentB is still in memory when I come back to FragmentA holding the instances of PopupWindow, View1 and View2. None of them are released. FragmentB should not be in memory.
Please help me out.
Here is my DemoPopupWindow.java
public class DemoPopupWindow extends PopupWindow {
// Views
private TabLayout mTabLayout;
private CustomViewPager mViewPager;
private PagerAdapter mViewPagerAdapter;
private RelativeLayout mLayout;
private View mRootView;
// Variables
private int mGreyColor, mPrimaryColor;
private OnSoftKeyboardOpenCloseListener onSoftKeyboardOpenCloseListener;
private int keyBoardHeight = 0;
private Boolean pendingOpen = false;
private Boolean isOpened = false;
private Context mContext;
ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
mRootView.getWindowVisibleDisplayFrame(r);
int screenHeight = mRootView.getRootView().getHeight();
int heightDifference = screenHeight - (r.bottom);
if (heightDifference > 100) {
keyBoardHeight = heightDifference;
setSize(WindowManager.LayoutParams.MATCH_PARENT, keyBoardHeight);
if (isOpened == false) {
if (onSoftKeyboardOpenCloseListener != null)
onSoftKeyboardOpenCloseListener.onKeyboardOpen(keyBoardHeight);
}
isOpened = true;
if (pendingOpen) {
showAtBottom();
pendingOpen = false;
}
} else {
isOpened = false;
if (onSoftKeyboardOpenCloseListener != null)
onSoftKeyboardOpenCloseListener.onKeyboardClose();
}
}
};
/**
* Constructor
* #param rootView
* #param mContext
*/
public DemoPopupWindow(View rootView, Context mContext){
super(mContext);
this.mContext = mContext;
this.mRootView = rootView;
Resources resources = mContext.getResources();
View customView = createCustomView(resources);
setContentView(customView);
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
setSize((int) mContext.getResources().getDimension(R.dimen.keyboard_height), WindowManager.LayoutParams.MATCH_PARENT);
}
/**
* Set keyboard close listener
* #param listener
*/
public void setOnSoftKeyboardOpenCloseListener(OnSoftKeyboardOpenCloseListener listener){
this.onSoftKeyboardOpenCloseListener = listener;
}
/**
* Show PopupWindow
*/
public void showAtBottom(){
showAtLocation(mRootView, Gravity.BOTTOM, 0, 0);
}
/**
* Show PopupWindow at bottom
*/
public void showAtBottomPending(){
if(isKeyBoardOpen())
showAtBottom();
else
pendingOpen = true;
}
/**
* Check whether keyboard is open or not
* #return
*/
public Boolean isKeyBoardOpen(){
return isOpened;
}
/**
* Set soft keyboard size
*/
public void setSizeForSoftKeyboard(){
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
/**
* Remove global layout listener
*/
public void removeGlobalListener() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
mRootView.getViewTreeObserver().removeGlobalOnLayoutListener(mGlobalLayoutListener);
} else {
mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
}
}
/**
* Set PopupWindow size
* #param width
* #param height
*/
public void setSize(int width, int height){
keyBoardHeight = height;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, keyBoardHeight);
mLayout.setLayoutParams(params);
setWidth(width);
setHeight(height);
}
/**
* Create PopupWindow View
* #return
*/
private View createCustomView(Resources resources) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.popup, null, false);
mViewPager = (CustomViewPager) view.findViewById(R.id.pager);
mLayout = (RelativeLayout) view.findViewById(R.id.layout);
mViewPagerAdapter = new ViewPagerAdapter(
Arrays.asList(
new View1(mContext, this),
new View2(mContext, this)
)
);
mViewPager.setAdapter(mViewPagerAdapter);
mPrimaryColor = resources.getColor(R.color.color_primary);
mGreyColor = resources.getColor(R.color.grey_color);
mTabLayout = (TabLayout) view.findViewById(R.id.tabs);
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.addTab(mTabLayout.newTab());
mTabLayout.setupWithViewPager(mViewPager);
return view;
}
/**
* ViewPager Adapter
*/
private static class ViewPagerAdapter extends PagerAdapter {
private List<ViewBase> views;
public ViewPagerAdapter(List<ViewBase> views) {
super();
this.views = views;
}
#Override
public int getCount() {
return views.size();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View v = views.get(position).mRootView;
((ViewPager)container).addView(v, 0);
return v;
}
#Override
public void destroyItem(ViewGroup container, int position, Object view) {
((ViewPager)container).removeView((View)view);
}
#Override
public boolean isViewFromObject(View view, Object key) {
return key == view;
}
}
/**
* Soft keyboard open close listener
*/
public interface OnSoftKeyboardOpenCloseListener{
void onKeyboardOpen(int keyBoardHeight);
void onKeyboardClose();
}
}
Please note that I haven't pasted complete PopupWindow class here but only the necessary part.
Here is how I am using this DemoPopupWindow in my FragmentB
mPopupWindow = new DemoPopupWindow(mLayout, getActivity());
mPopupWindow.setSizeForSoftKeyboard();
// If the text keyboard closes, also dismiss the PopupWindow
mPopupWindow.setOnSoftKeyboardOpenCloseListener(new DemoPopupWindow.OnSoftKeyboardOpenCloseListener() {
#Override
public void onKeyboardOpen(int keyBoardHeight) {
}
#Override
public void onKeyboardClose() {
if (mPopupWindow.isShowing())
mPopupWindow.dismiss();
}
});
In FragmentB onDestroy I am calling this method to remove GlobalLayoutListener
mPopupWindow.removeGlobalListener();
I have a button in FragmentB to show and dismiss PopupWindow.
Here is my ViewBase.java
public class ViewBase {
public View mRootView;
DemoPopupWindow mPopup;
private Context mContext;
public ViewBase (Context context, DemoPopupWindow popup) {
mContext = context;
mPopup = popup;
}
public ViewBase () {
}
}
Here is my View1
public class View1 extends ViewBase{
// Views
public View mRootView;
DemoPopupWindow mPopup;
private LinearLayout mLayoutText;
// Variables
private Context mContext;
private List<String> mText;
/**
* Constructor
*/
public View1(Context context, DemoPopupWindow popup) {
super(context, popup);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
mPopup = popup;
mRootView = inflater.inflate(R.layout.fragment_view1, null);
mContext = context;
// Set parent class rootview
super.mRootView = mRootView;
registerViews(mRootView);
registerListeners();
populateText();
}
/**
* Register all the views
* #param view
*/
private void registerViews(View view) {
mLayoutText = (LinearLayout) view.findViewById(R.id.view1_layout);
mText = TextManager.getInstance().getText();
}
/**
* Populate text
*/
private void populateText() {
int length = mText.size();
for(int i=0; i<length; i++) {
addNewText(mText.get(i).getText());
}
}
/**
* Add new text
* #param text
*/
private void addNewText(final String text) {
TextView textView = createTextView(text);
mLayoutText.addView(textView);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do something
}
});
}
/**
* Create textview
* #param text
* #return
*/
private TextView createTextView(final String text) {
TextView textView = new TextView(mContext);
FlowLayout.LayoutParams params = new FlowLayout.LayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, 40);
params.setMargins(4, 4, 0, 0);
textView.setLayoutParams(params);
textView.setClickable(true);
textView.setGravity(Gravity.CENTER);
textView.setPadding(10, 0, 10, 0);
textView.setText(text);
textView.setTextSize(20);
return textView;
}
}
EDIT AGAIN:
I have found the issue but I dont know how to fix it. The problem is with mGlobalLayoutListener. This is holding the reference of some view. If I don't use GlobalLayoutListener at all then the FragmentB instance is getting removed from the memory.
Even after calling removeGlobalLayout(), this listener is not getting released. Please help me out.
are you sure CustomPopupWindow is causing you memory leak? Have you done garbage collection before running heap dump, maybe there is no leak at all..?
It's called onDestroy in FragmentB with popup when you goes back to fragmentA?
How to remove safely GlobalLayoutListener ?
Caution of your Android version, since api is deprecated! :)
Can you try this
if (Build.VERSION.SDK_INT < 16) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
} else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}

Listview in Fragment is causing Memory Leak

I have a FragmentActivity with a FragmentMediaOverview containing a list of MediaItemViews (each with a imageview and some text) and a click on one of the items opening a detail-Fragment.
Now when I go back (via back button) and forth (click on listitem) several times from list to detail fragment I eventually run into OOM-Errors. I use SoftReferences for the bitmaps in the listitems as well as in the detail fragment.
According to MAT there is an incresing number of MediaItemViews as well as FragmentMediaOverview instances, but I just cannot figure out why.
I read this Android: AlertDialog causes a memory leak , but couldn't solve it nulling out listeners.
Here is my code:
FragmentMediaOverview.java
(This is not a ListFragment because for a tablet-layout the MediaAdapter needs to connect to a gridview)
public class FragmentMediaOverview extends Fragment {
private static String TAG = FragmentMediaOverview.class.getSimpleName();
private MediaAdapter adapter;
private OnMediaSelectedListener selListener;
private ArrayList<BOObject> mediaItems;
private ViewGroup layoutContainer;
private AdapterView itemContainer; // list or gridview
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
layoutContainer = (ViewGroup) inflater.inflate(R.layout.fragment_media_overview, null);
return layoutContainer;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
selListener = (OnMediaSelectedListener) activity;
}
#Override
public void onDestroy() {
super.onDestroy();
itemContainer.setOnItemClickListener(null);
selListener = null;
adapter = null;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initUi(layoutContainer);
displayMedia();
}
private void initUi(ViewGroup layoutContainer) {
itemContainer = (AdapterView) layoutContainer.findViewById(android.R.id.list);
itemContainer.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BOMedia mediaItem = ((BOMedia) mediaItems.get(position));
//the FragmentActivity is coordinating the FragmentTransactions
selListener.onMediaSelected(mediaItem);
}
});
}
private void displayMedia() {
Log.d(TAG, "Displaying List");
if (mediaItems == null) {
loadMedia();
return;
}
Log.d(TAG, "List: " + mediaItems.size() + ", adapter: " + itemContainer.getAdapter());
if (adapter == null) {
Log.d(TAG, "Create Adapter with " + mediaItems.size());
adapter = new MediaAdapter(getActivity(), mediaItems);
}
if (itemContainer.getAdapter() == null) {
itemContainer.setAdapter(adapter);
} else {
adapter.setItems(mediaItems);
adapter.notifyDataSetChanged();
}
}
private void loadMedia() {
FragmentHelper.showProgressSpinner(layoutContainer, android.R.id.list);
DbHelper.getInstance().getMedia(mediaType, new DbQueryFinishListener() {
#Override
public void onDbCallFinish(ArrayList<BOObject> objects) {
if (!getActivity().isFinishing()) {
mediaItems = objects;
Collections.sort(mediaItems, new Comparator<BOObject>() {
final Collator c = Collator.getInstance(Locale.GERMAN);
#Override
public int compare(BOObject s1, BOObject s2) {
if (s2 != null && ((BOMedia) s2).getTitle() != null && s1 != null
&& ((BOMedia) s1).getTitle() != null) {
return c.compare(((BOMedia) s1).getTitle(),((BOMedia) s2).getTitle());
} else {
return 0;
}
}
});
displayMedia();
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
#Override
public void onDbCallException(Exception exception) {
if (!getActivity().isFinishing()) {
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
});
}
}
MediaAdapter.java
public class MediaAdapter extends BaseAdapter {
private static final String TAG = MediaAdapter.class.getSimpleName();
private Context context;
private ArrayList<BOObject> mediaItems;
public MediaAdapter(Context c, ArrayList<BOObject> mediaItems) {
super();
context = c;
this.mediaItems = mediaItems;
}
#Override
public int getCount() {
return mediaItems.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = new MediaItemView(context);
}
((MediaItemView)convertView).initialize((BOMedia) mediaItems.get(position));
return convertView;
}
public void setItems(ArrayList<BOObject> mediaItems) {
this.mediaItems = mediaItems;
}
}
MediaItemView.java
public class MediaItemView extends LinearLayout {
private static final String TAG = MediaItemView.class.getSimpleName();
private BOMedia item;
private SoftReference<Bitmap> bm;
private ImageView iv;
private Context ctx;
public MediaItemView(Context context) {
super(context);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_media_item, this);
this.ctx = context;
}
/** Init the view with a new BOMedia object
* #param mediaItem
*/
public void initialize(BOMedia mediaItem) {
this.item = mediaItem;
initUI();
}
private void initUI() {
TextView title = (TextView) findViewById(R.id.itemText);
iv = (ImageView) findViewById(R.id.itemImage);
title.setText(Html.fromHtml(item.getTitle()));
iv.setImageBitmap(null);
bm = null;
System.gc();
iv.invalidate();
if (item.getFilepathThumb() != null && !item.getFilepathThumb().equals("")) {
ExpansionPackManager.getInstance().getBitmapResource(item.getFilepathThumb(), false,
new BitmapReadListener() {
#Override
public void onFileRead(BitmapResponseMessage message) {
Log.d(TAG, "Bitmap read: " + message.getFilepath());
Bitmap image = message.getBitmap();
if (image != null && message.getFilepath().equals(item.getFilepathThumb())) {
bm = new SoftReference<Bitmap>(image);
iv.setImageBitmap(bm.get());
Log.d(TAG, "image set");
} else {
Log.d(TAG, "image too late: " + image);
}
}
#Override
public void onFileException(Throwable exception) {
Log.d(TAG, "image exception");
}
});
}
}
}
In MediaItemView the size of your bitmap must be too big. If the bitmap is 600x600 and you want to display a image with a size of 50x50 you can use Bitmap.createScaledBitmap. You should also use bitmap cache while loading your bitmap.
This is because the View for rach child in the ListView is recreated as you scroll through. This is very heavy on resources. To avoid this use a holder class in adapters getView() to hold and reuse the views. This is called an Efficient Adapter. For example see Efficient List Adapter in API demos. http://developer.android.com/tools/samples/index.html
You can also use:
android:hardwareAccelerated = true
Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline is designed to better support hardware acceleration. Hardware acceleration carries out all drawing operations that are performed on a View's canvas using the GPU.
For more info http://developer.android.com/guide/topics/graphics/hardware-accel.html

Categories

Resources