"OutOfMemoryError" When scrolling images in the ListView - java

10-16 21:49:03.318 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Grow heap (frag case) to 171.874MB for 14400016-byte allocation
10-16 21:49:03.578 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Grow heap (frag case) to 175.314MB for 14400016-byte allocation
10-16 21:49:03.689 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Grow heap (frag case) to 177.603MB for 3600016-byte allocation
10-16 21:49:03.839 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Grow heap (frag case) to 178.716MB for 14364016-byte allocation
10-16 21:49:04.029 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Grow heap (frag case) to 182.185MB for 14400016-byte allocation
10-16 21:49:04.139 29852-29852/com.klau.jobsinaustralia I/dalvikvm-heap: Forcing collection of SoftReferences for 3600016-byte allocation
10-16 21:49:04.199 29852-29852/com.klau.jobsinaustralia E/dalvikvm-heap: Out of memory on a 3600016-byte allocation.
10-16 21:49:04.199 29852-29852/com.klau.jobsinaustralia I/dalvikvm: "main" prio=5 tid=1 RUNNABLE
10-16 21:49:08.223 29852-29852/com.klau.jobsinaustralia E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.OutOfMemoryError: (Heap Size=194912KB, Allocated=182627KB)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:628)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:475)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:504)
at com.klau.jobsinaustralia.scrollable.CustomList.decodeSampledBitmapFromResource
Activity
public class ExtraInfoActivity extends BaseActivity {
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
final String languageToLoad = sharedPreferences.getString("PREF_LIST", "no selection");
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,getBaseContext().getResources().getDisplayMetrics());
setContentView(R.layout.activity_extra_info);
String[] nsw_attraction = {
"Sydney Bridge",
"Blue Mountains",
"Bondi Beach",
"The Hunter Valley",
"The Jenolan Caves"
};
final String[] nsw_web = {
getResources().getString(R.string.nsw_attraction_1),
getResources().getString(R.string.nsw_attraction_2),
getResources().getString(R.string.nsw_attraction_3),
getResources().getString(R.string.nsw_attraction_4),
getResources().getString(R.string.nsw_attraction_5)
};
Integer[] nswImageId = {
R.drawable.nsw_attraction_bridge,
R.drawable.nsw_attraction_blue_mountains,
R.drawable.nsw_attraction_bondi_beach,
R.drawable.nsw_attraction_hunter_valley,
R.drawable.nsw_attraction_jenolan_caves
};
CustomList adapter = new CustomList(ExtraInfoActivity.this, nsw_attraction, nsw_web, nswImageId);
list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(ExtraInfoActivity.this, nsw_web[+position], Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onStart() {
super.onStart();
try {
mTracker.setScreenName("Extra Infomation");
mTracker.send(new HitBuilders.AppViewBuilder().build());
}catch (Exception ex){
ex.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_home, menu);
return true;
}
}

You need to use a library to load the images in the ListView.
Glide is an amazing library to load the images.
It's setup is very simple:
Put these two in your build.gradle:
dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.support:support-v4:19.1.0'
}
and then in your adapter all you need to do is:
Glide
.with(context)
.load(nswImageId[position])
.into(myImageView);
That's it, it will take care of everything. You can find more information and usage details here.

I have already resized the image. my CustomList Class below
public class CustomList extends ArrayAdapter{
private final Activity context;
private final String[] placeName;
private final String[] web;
private final Integer[] imageId;
public CustomList(Activity context, String[] placeName, String[] web, Integer[] imageId) {
super(context, R.layout.list_single, web);
this.context = context;
this.placeName = placeName;
this.web = web;
this.imageId = imageId;
}
#Override
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView place = (TextView) rowView.findViewById(R.id.place_name);
place.setText(placeName[position]);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
txtTitle.setText(web[position]);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
Bitmap bitmap = decodeSampledBitmapFromResource(context.getResources(), imageId[position], 150, 150);
if (bitmap != null) {
bitmap.recycle(); //<====== ERROR here: java.lang.IllegalArgumentException: Cannot draw recycled bitmap.
}
imageView.setImageBitmap(bitmap);
return rowView;
}
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) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
}

Use Picasso Library.Its so easy to use and handle many other error also.
http://square.github.io/picasso/

many thanks for a quick answer. Not sure i can do it correctly. please reiew my changes.
#Override
public View getView(int position, View view, ViewGroup parent) {
final ImageView myImageView;
LayoutInflater inflater = context.getLayoutInflater();
View rowView= inflater.inflate(R.layout.list_single, null, true);
TextView place = (TextView) rowView.findViewById(R.id.place_name);
place.setText(placeName[position]);
TextView txtTitle = (TextView) rowView.findViewById(R.id.txt);
txtTitle.setText(web[position]);
ImageView imageView = (ImageView) rowView.findViewById(R.id.img);
if (view == null) {
myImageView = (ImageView) inflater.inflate(imageView, parent, false);
} else {
myImageView = (ImageView) recycled;
}
Glide
.with(context)
.load(nswImageId[position])
.into(myImageView);
return myImageView;
}

write this line in application tag in your manifest file
android:largeHeap="true"

Related

java.lang.OutOfMemoryError after returning to activity

I am trying to make a slide show using viewPager in Android Studio. I use BitmapFactory.Options to resize images if they are too "large", also I use in manifest the following code android:largeHeap="true"
android:allowBackup="true"
I want to specify that the above code does not work in my case, if I not use BitmapFactory.Options to resize the images I get the error java.lang.OutOfMemoryError.
Here is the code for adapter
public class SlideShowAdapter extends PagerAdapter {
private Context context;
private LayoutInflater inflater;
private final int HEIGHT_IMGAE = 230;
private int [] images = {
R.drawable.img1,
R.drawable.img2,
R.drawable.img3
};
public SlideShowAdapter(Context context) {
this.context = context;
}
#Override
public int getCount() {
return images.length;
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return (view == object);
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.slide_show_layout, container, false);
ImageView img = view.findViewById(R.id.sile_show_layout_imageView);
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
img.setImageBitmap(
decodeSampledBitmapFromResource(context.getResources(), images[position], width, HEIGHT_IMGAE));
container.addView(view);
return view;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((LinearLayout)object);
}
private 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;
}
private 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);
}
}
Everything works fine in main
public class MainActivity extends AppCompatActivity {
private ViewPager slideShow;
private SlideShowAdapter adapter ;
private int currentPage = 0;
Timer timer;
final long DELAY_MS = 3000; //delay in milliseconds before task is to be executed
final long PERIOD_MS = 5000; // time in milliseconds between successive task executions.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
slideShow = findViewById(R.id.main_activity_viewPager_slideshow);
adapter = new SlideShowAdapter(this);
slideShow.setAdapter(adapter);
this.doSlideShow();
}
public void doSlideShow(){
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == adapter.getCount()) {
currentPage = 0;
}
slideShow.setCurrentItem(currentPage++, true);
}
};
timer = new Timer(); // This will create a new Thread
timer.schedule(new TimerTask() { // task to be scheduled
#Override
public void run() {
handler.post(Update);
}
}, DELAY_MS, PERIOD_MS);
}
public void luchAdminActivity(View view) {
startActivity(new Intent(this,SingupActivity.class));
}
public void luchMainActivity(View view) {
startActivity(new Intent(this,MainActivity.class));
}
public void luchMenuActivity(View view) {
startActivity(new Intent(this,MainActivity.class));
}
}
but when I go to another Activity and try to return to Main Activity(where I have the slide show) I get the following error
Process: bogdan.yourwaiter, PID: 25647
java.lang.OutOfMemoryError: Failed to allocate a 156487692 byte allocation with 16768376 free bytes and 114MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:700)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:535)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:558)
at bogdan.yourwaiter.adapter.SlideShowAdapter.decodeSampledBitmapFromResource(SlideShowAdapter.java:111)
at bogdan.yourwaiter.adapter.SlideShowAdapter.instantiateItem(SlideShowAdapter.java:61)
at androidx.viewpager.widget.ViewPager.addNewItem(ViewPager.java:1010)
at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1224)
at androidx.viewpager.widget.ViewPager.populate(ViewPager.java:1092)
at androidx.viewpager.widget.ViewPager.onMeasure(ViewPager.java:1622)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1117)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:642)
at android.view.View.measure(View.java:21121)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:401)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1464)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:758)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:640)
at android.view.View.measure(View.java:21121)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6462)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:185)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:872)
at android.view.View.measure(View.java:21121)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2625)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1677)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1928)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1550)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7190)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959)
at android.view.Choreographer.doCallbacks(Choreographer.java:734)
at android.view.Choreographer.doFrame(Choreographer.java:670)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

How to make an image shower larger from thumbnail in android?

I Have successfully started reading images back into my android app into a gridview, I need help now. When a user clicks on an image I want it to appear larger from the thumbnail. Any help is much appreciated.
My code for the images to get read :
[code]
public class View_Pictures extends AppCompatActivity {
public class ImageAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> itemList = new ArrayList<String>();
public ImageAdapter(Context c) {
mContext = c;
}
void add(String path){
itemList.add(path);
}
#Override
public int getCount() {
return itemList.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220);
imageView.setImageBitmap(bm);
return imageView;
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public 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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
ImageAdapter myImageAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view__pictures);
GridView gridview = (GridView) findViewById(R.id.gridview);
myImageAdapter = new ImageAdapter(this);
gridview.setAdapter(myImageAdapter);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/Venns Road Accident";
Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myImageAdapter.add(file.getAbsolutePath());
}
}
}
Gridview
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/textView47"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
you can use photoviwer library which is used to show full detail image on seperate activity .
// Any implementation of ImageView can be used!
mImageView = (ImageView) findViewById(R.id.iv_photo);
// Set the Drawable displayed
Drawable bitmap = getResources().getDrawable(R.drawable.wallpaper);
// or
// get your bitmap here
mImageView.setImageDrawable(bitmap);
// Attach a PhotoViewAttacher, which takes care of all of the zooming functionality.
// (not needed unless you are going to change the drawable later)
mAttacher = new PhotoViewAttacher(mImageView);
please refer below link
https://github.com/chrisbanes/PhotoView

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.
Edit: 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);

Grow Heaps in Android ListView

In a nutshell, I have a ListView and when I scroll through it, I get grow heaps and on the device I can see it hooking. I've read something about recycling Bitmaps, but I haven't found a solution for doing this in my project.
TeamFragment.java:
public class TeamFragment extends ListFragment implements OnItemClickListener {
private TeamListAdapter adapter;
public TeamFragment() {}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.fragmentNumber = getArguments().getInt(ARG_FRAGMENT_NUMBER);
adapter = new TeamListAdapter(this.getActivity());
setListAdapter(adapter);
getListView().setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view,
int position, long id) {
Intent intent = new Intent(view.getContext(), TeamDetailActivity.class);
Bundle extra = new Bundle();
extra.putInt("drawable", adapter.getItem(position).getDrawable());
extra.putString("name", adapter.getItem(position).getName());
extra.putString("title", adapter.getItem(position).getTitle());
extra.putString("description", adapter.getItem(position).getDescription());
intent.putExtra("extra", extra);
startActivityForResult(intent, 0);
}
}
TeamListAdapter.java
public class TeamListAdapter extends BaseAdapter {
private final LayoutInflater inflater;
private final List<HumanItem> humanItems;
private String[] teamname_array;
private String[] teamname_extra_array;
private String[] teamdescription_array;
private String[] teamid_array;
public TeamListAdapter(Context context) {
inflater = LayoutInflater.from(context);
humanItems = new ArrayList<HumanItem>();
teamid_array = context.getResources().getStringArray(
R.array.teamids);
teamname_array = context.getResources().getStringArray(
R.array.teamnames);
teamname_extra_array = context.getResources().getStringArray(
R.array.teamnames_extra);
teamdescription_array = context.getResources().getStringArray(
R.array.teamdescriptions);
HumanItem tmp;
int resId;
int i = 0;
for(String name : teamid_array) {
resId = context.getResources().getIdentifier("team_" + name, "drawable", context.getPackageName());
tmp = new HumanItem(name, resId, teamname_array[i], teamname_extra_array[i], teamdescription_array[i]);
String TAG = TeamListAdapter.class.getSimpleName();
Log.d(TAG , "team_" + name);
i++;
humanItems.add(tmp);
}
}
#Override
public int getCount() {
return humanItems.size();
}
#Override
public HumanItem getItem(int position) {
return humanItems.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// build contentView if necessary
if (convertView == null) {
convertView = inflater.inflate(R.layout.fragment_news, parent,
false);
// create holder
holder = new ViewHolder();
holder.bubble = (TextView) convertView
.findViewById(R.id.news_bubble);
holder.title = (TextView) convertView.findViewById(R.id.news_title);
holder.summary = (TextView) convertView
.findViewById(R.id.news_summary);
holder.teaser = (ImageView) convertView
.findViewById(R.id.news_drawable);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// Context context = parent.getContext();
HumanItem humanItem = getItem(position);
holder.bubble.setVisibility(View.GONE);
holder.title.setText(humanItem.getTitle());
holder.summary.setText(humanItem.getSummary());
holder.teaser.setImageResource(humanItem.getDrawable());
return convertView;
}
static class ViewHolder {
TextView bubble, title, summary;
ImageView teaser;
}
}
One of the many grow heaps:
12-31 13:49:31.756: I/dalvikvm-heap(27543): Grow heap (frag case) to 23.180MB for 2569892-byte allocation
So where do I have to recycle Bitmaps? Or is there another way of preventing grow heaps?
Actually it is not good to do what you want as eventually you will get the outOfMemoryError.
To handle bitmap You can see my answer here.It will be useful to handle your bitmap efficiently.
Just check it out..!
How to make application more responsive which uses several bitmaps?
If you need to show a list of images, I suggest to check this library, I used this library and works really fine with 0 freezes and estable heap: Universal Image Loader

Popup gridview cell onTOuch

I have a grid View In which I am adding Button dynamically.
I am setting OnTouch listener to grid view.
I want when my finger move on the particular cell then that cell element should get popup
similar way our android keyboard do.
public class MainActivity extends Activity {
private ArrayList<Integer> data;
private GridView gv;
private TextView biggerView = null;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createData();
gv = (GridView) findViewById(R.id.grid);
gv.setNumColumns(10);
gv.setAdapter(new FilterButtonAdapter(data, this));
gv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
try {
int position = gv.pointToPosition((int) event.getX(),
(int) event.getY());
View v = (View) gv.getChildAt(position);
if (v != null) {
gv.requestFocus();
gv.setSelection(gv.pointToPosition( (int)
event.getX(), (int) event.getY()));
}
return true;
} catch (Exception e) {
return true;
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
int position = gv.pointToPosition((int) event.getX(),
(int) event.getY());
View v = (View) gv.getChildAt(position);
if (v != null) {
gv.clearFocus();
TextView tv = (TextView) v.findViewById(R.id.texttoadd);
Toast.makeText(MainActivity.this, tv.getText(),
Toast.LENGTH_SHORT).show();
}
return true;
}
return false;
}
});
}
private void createData() {
data = new ArrayList<Integer>();
for (int i = 0; i < 200; i++) {
data.add(i);
}
}
enter code here
i have write this code which is giving me the selected item but when item are more then grid is scrolled and after that the am not getting the item which i am selecting
i have figured out that the x and y position is getting change when grid is scrolled
i may be wrong
please help
I think that suggested in the question way of touch position detection might be not effective, because there's more high-level way to obtain scrolling position.
The main ideas of the implementation are the following:
Use onScrollChanged() to track scroll position at every moment;
Display selection as separate view above GridView;
Track if selected item is visible (using this question);
So, to obtain proper scroll callback, slightly customized GridView is needed:
public class ScrollAwareGridView extends GridView {
/** Callback interface to report immediate scroll changes */
public interface ImmediateScrollListener {
void onImmediateScrollChanged();
}
/** External listener for */
private ImmediateScrollListener mScrollListener = null;
public ScrollAwareGridView(final Context context) {
super(context);
}
public ScrollAwareGridView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public ScrollAwareGridView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (null != mScrollListener) {
mScrollListener.onImmediateScrollChanged();
}
}
/**
* #param listener {#link ImmediateScrollListener}
*/
public void setImmediateScrollListener(final ImmediateScrollListener listener) {
mScrollListener = listener;
}
}
It will be placed in the xml the following way (main.xml):
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.TestApp.ScrollAwareGridView
android:id="#+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="3" />
<!-- Selection view -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/selectedImage"
android:visibility="gone" />
</RelativeLayout>
In above xml there's also selection view presented.
Activity will handle selection of items (however, it might be better to keep selection and scroll tracking logic in separate object (grid adapter or specific grid fragment) in order not to keep grid-specific logic in Activity code):
public class MyActivity extends Activity implements ScrollAwareGridView.ImmediateScrollListener, AdapterView.OnItemClickListener {
private static final String TAG = "MyActivity";
/** To start / pause music */
private ImageView mSelectedImage = null;
/** position of selected item in the adapter */
private int mSelectedPosition;
/** Main grid view */
private ScrollAwareGridView mGrid;
/** Adapter for grid view */
private ImageAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show the layout with the test view
setContentView(R.layout.main);
mSelectedImage = (ImageView) findViewById(R.id.selectedImage);
mGrid = (ScrollAwareGridView) findViewById(R.id.grid);
if (null != mGrid) {
mAdapter = new ImageAdapter(this);
mGrid.setAdapter(mAdapter);
mGrid.setImmediateScrollListener(this);
mGrid.setOnItemClickListener(this);
}
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
mSelectedImage.setImageBitmap(null);
mSelectedImage.setVisibility(View.GONE);
mSelectedPosition = -1;
}
#Override
public void onImmediateScrollChanged() {
if (mSelectedPosition >= 0) {
int firstPosition = mGrid.getFirstVisiblePosition(); // This is the same as child #0
int wantedChild = mSelectedPosition - firstPosition;
// Say, first visible position is 8, you want position 10, wantedChild will now be 2
// So that means your view is child #2 in the ViewGroup:
if (wantedChild < 0 || wantedChild >= mGrid.getChildCount()) {
Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
mSelectedImage.setVisibility(View.INVISIBLE);
return;
} else {
mSelectedImage.setVisibility(View.VISIBLE);
}
// Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
final View selectedView = mGrid.getChildAt(wantedChild);
if (null != selectedView && mSelectedImage.getVisibility() == View.VISIBLE) {
// Put selected view on new position
final ViewGroup.MarginLayoutParams zoomedImageLayoutParams = (ViewGroup.MarginLayoutParams) mSelectedImage.getLayoutParams();
// 200 is difference between zoomed and not zoomed images dimensions
// TODO: Avoid hardcoded values and use resources
final Integer thumbnailX = mGrid.getLeft() + selectedView.getLeft() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
final Integer thumbnailY = mGrid.getTop() + selectedView.getTop() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
zoomedImageLayoutParams.setMargins(thumbnailX,
thumbnailY,
0,
0);
mSelectedImage.setLayoutParams(zoomedImageLayoutParams);
}
}
}
#Override
public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
mSelectedPosition = position;
final Bitmap bm = mAdapter.getImage(position);
// Obtain image from adapter, with check if image presented
if (bm != null) {
final ViewGroup.MarginLayoutParams zoomedImageLayoutParams = (ViewGroup.MarginLayoutParams) mSelectedImage.getLayoutParams();
// 200 is difference between zoomed and not zoomed images dimensions
// TODO: Avoid hardcoded values and use resources
final Integer thumbnailX = mGrid.getLeft() + view.getLeft() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
final Integer thumbnailY = mGrid.getTop() + view.getTop() - (ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION - ImageAdapter.GRID_ITEM_DIMENSION) / 2;
zoomedImageLayoutParams.setMargins(thumbnailX,
thumbnailY,
0,
0);
zoomedImageLayoutParams.height = ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION;
zoomedImageLayoutParams.width = ImageAdapter.HIGHLIGHTED_GRID_ITEM_DIMENSION;
mSelectedImage.setImageBitmap(bm);
mSelectedImage.setScaleType(ImageView.ScaleType.CENTER);
mSelectedImage.setLayoutParams(zoomedImageLayoutParams);
mSelectedImage.setVisibility(View.VISIBLE);
}
}
}
Below is GridViews adapter. However there's nothing specific in it which related to scrolling tracking (most of code I've reused from this answer):
public class ImageAdapter extends BaseAdapter {
private static final String TAG = "ImageAdapter";
/** For creation of child ImageViews */
private Context mContext;
public static final Integer[] IMAGES_RESOURCES = {
R.drawable.image001, R.drawable.image002, R.drawable.image003, R.drawable.image004,
R.drawable.image005, R.drawable.image006, R.drawable.image007, R.drawable.image008,
R.drawable.image009, R.drawable.image010, R.drawable.image011, R.drawable.image012,
R.drawable.image013, R.drawable.image014, R.drawable.image015, R.drawable.image016,
R.drawable.image017, R.drawable.image018, R.drawable.image019, R.drawable.image020,
R.drawable.image021, R.drawable.image022, R.drawable.image023, R.drawable.image024,
R.drawable.image025, R.drawable.image026, R.drawable.image027, R.drawable.image028,
R.drawable.image029, R.drawable.image030, R.drawable.image031, R.drawable.image032,
R.drawable.image033, R.drawable.image034, R.drawable.image035, R.drawable.image036,
R.drawable.image037, R.drawable.image038, R.drawable.image039, R.drawable.image040,
R.drawable.image041, R.drawable.image042, R.drawable.image043, R.drawable.image044,
R.drawable.image045, R.drawable.image046, R.drawable.image047, R.drawable.image048,
R.drawable.image049, R.drawable.image050
};
// TODO: use resources for that sizes, otherwise You'll GET PROBLEMS on other displays!
public final static int GRID_ITEM_DIMENSION = 300;
public final static int HIGHLIGHTED_GRID_ITEM_DIMENSION = 500;
private Bitmap mHolder = null;
private static final int CACHE_SIZE = 50 * 1024 * 1024; // 8 MiB cache
/** Cache to store all decoded images */
private LruCache<Integer, Bitmap> mBitmapsCache = new LruCache<Integer, Bitmap>(CACHE_SIZE) {
#Override
protected int sizeOf(final Integer key, final Bitmap value) {
return value.getByteCount();
}
#Override
protected void entryRemoved(final boolean evicted, final Integer key, final Bitmap oldValue, final Bitmap newValue) {
if (!oldValue.equals(mHolder)) {
oldValue.recycle();
}
}
};
// Constructor
public ImageAdapter(Context c){
mContext = c;
mHolder = BitmapFactory.decodeResource(c.getResources(), R.drawable.ic_launcher, null);
}
#Override
public int getCount() {
return IMAGES_RESOURCES.length;
}
#Override
public Object getItem(int position) {
return IMAGES_RESOURCES[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(GRID_ITEM_DIMENSION, GRID_ITEM_DIMENSION));
} else {
imageView = (ImageView) convertView;
}
final Bitmap itemBitmap = mBitmapsCache.get(IMAGES_RESOURCES[position]);
if (itemBitmap == null || itemBitmap.isRecycled()) {
Log.e(TAG, position + " is missed, launch decode for " + IMAGES_RESOURCES[position]);
imageView.setImageBitmap(mHolder);
mBitmapsCache.put(IMAGES_RESOURCES[position], mHolder);
new BitmapWorkerTask(mBitmapsCache, mContext.getResources(), this).execute(IMAGES_RESOURCES[position]);
} else {
Log.e(TAG, position + " is here for " + IMAGES_RESOURCES[position]);
imageView.setImageBitmap(itemBitmap);
}
return imageView;
}
/**
* Obtains image at position (if there's only holder, then null to be returned)
*
* #param position int position in the adapter
*
* #return {#link Bitmap} image at position or null if image is not loaded yet
*/
public Bitmap getImage(final int position) {
final Bitmap bm = mBitmapsCache.get(IMAGES_RESOURCES[position]);
return ((mHolder.equals(bm) || bm == null) ? null : bm.copy(Bitmap.Config.ARGB_8888, false));
}
/** AsyncTask for decoding images from resources */
static class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private int data = 0;
private final LruCache<Integer, Bitmap> mCache;
private final Resources mRes;
private final BaseAdapter mAdapter;
public BitmapWorkerTask(LruCache<Integer, Bitmap> cache, Resources res, BaseAdapter adapter) {
// nothing to do here
mCache = cache;
mRes = res;
mAdapter = adapter;
}
// Decode image in background.
#Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
// Use sizes for selected bitmaps for good up-scaling
return decodeSampledBitmapFromResource(mRes, data, GRID_ITEM_DIMENSION, GRID_ITEM_DIMENSION);
}
// Once complete, see if ImageView is still around and set bitmap.
#Override
protected void onPostExecute(Bitmap bitmap) {
mCache.put(data, bitmap);
mAdapter.notifyDataSetChanged();
}
}
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;
options.outHeight = GRID_ITEM_DIMENSION;
options.outWidth = GRID_ITEM_DIMENSION;
return BitmapFactory.decodeResource(res, resId, options);
}
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) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
}

Categories

Resources