What can be cause for this error:
java.lang.OutOfMemoryError: Failed to allocate a 10111384 byte allocation with 1305618 free bytes and 1275KB until OOM
Error happens in this line :
Bitmap bmp = BitmapFactory.decodeByteArray(currentTour.getTourImage(),0,currentTour.getTourImage().length);
My ListView adapter View :
public View getView(int position, View view, ViewGroup parent) {
if (view == null)
view = getLayoutInflater().inflate(R.layout.tour_item, parent, false);
if (position % 2 == 1) {
view.setBackgroundColor(Color.rgb(189, 230, 247));
} else {
view.setBackgroundColor(Color.WHITE);
}
TourAnounceRow currentTour = tourAnounceList.get(position);
if (currentTour != null) {
TextView tourName = (TextView) view.findViewById(R.id.lblTourName);
tourName.setText(currentTour.getTourName());
TextView place = (TextView) view.findViewById(R.id.lblPlace);
place.setText(currentTour.getPlace());
RatingBar tourStarCount = (RatingBar) view.findViewById(R.id.ratingBarTourStarCount);
tourStarCount.setRating(Float.parseFloat(String.valueOf(currentTour.getHotelStarsCount())));
TextView adultCount = (TextView) view.findViewById(R.id.lblAdultCount);
adultCount.setText(String.valueOf(currentTour.getAdultCount()));
TextView childrenCount = (TextView) view.findViewById(R.id.lblChildCount);
childrenCount.setText(String.valueOf(currentTour.getChildrenCount()));
TextView mealCount = (TextView) view.findViewById(R.id.lblMealCount);
mealCount.setText(String.valueOf(currentTour.getDailyMealCount()));
TextView price = (TextView) view.findViewById(R.id.lblPrice);
price.setText(String.valueOf(currentTour.getPrice()));
ImageView ivTourImage = (ImageView) view.findViewById(R.id.ivTourImage);
ivTourImage.setScaleType(ImageView.ScaleType.FIT_XY);
Bitmap bmp = BitmapFactory.decodeByteArray(currentTour.getTourImage(), 0,currentTour.getTourImage().length);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.WEBP, 10, stream);
ivTourImage.setImageBitmap(bmp);
}
return view;
}
This happens because your bitmap it's to large, you can optimize the load of the bitmap, take a look to this link
I would suggest, especially since you're using this inside a ListView, that you take a look at the Glide Library (https://github.com/bumptech/glide). The library will handle both an asynchronous call to load the image, as well as the resizing of the image to fit your ImageView (saving memory).
You also seem to be hold a lot of byte[] images in memory (based on tourAnounceList), you want to only hold a reference to them when possible; either as a URL/URI or a local resource integer (R.drawable.my_image).
The code should look like this:
ImageView ivTourImage = (ImageView) view.findViewById(R.id.ivTourImage);
Glide.with(parent.getContext()).load(currentTour.getImageUrl())
.fitCenter().into(ivTourImage);
Related
I do have an app that shows images and some other text info from firebase-Realtime,
there is a problem with my app ram usage that it can easily cross over 400+mb
so i used profiler to check and solved every MemoryLeaks my app have, now when i checked the Android studio profiler i found that there is a ton of Bitmaps that are using loads of memory.
AlSO Iam using Picasso to load images into Recycleview from within Adapter
also using Glide sometimes
so i want to knew is it possible to solve these bitmap memory usage or is it possible to to limit number of bitmap that can be used, cuz every time a new image are shown the app would make a new bitmap and uses more Ram.
Adapter code to load Images into recyclerview:
public class HomeScreenWorkViewHolder extends RecyclerView.ViewHolder {
View view;
DatabaseReference likeReference;
public ImageView like_btn;
public TextView like_text;
public HomeScreenWorkViewHolder(#NonNull View itemView) {
super(itemView);
like_btn = itemView.findViewById(R.id.like_btn);
like_text = itemView.findViewById(R.id.like_text);
view = itemView;
}
public HomeScreenWorkViewHolder(#NonNull View itemView, OnItemClick callBack) {
super(itemView);
like_btn = itemView.findViewById(R.id.like_btn);
like_text = itemView.findViewById(R.id.like_text);
view = itemView;
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
callBack.onItemClicked(getAdapterPosition());
}
});
}
public void setdetails( String name, String image, String description, String location) {
TextView mtitletv = view.findViewById(R.id.product_layout_name);
TextView mdesrcriptiontv = view.findViewById(R.id.product_layout_description);
TextView mlocationtv = view.findViewById(R.id.product_layout_location);
ImageView mImagetv = view.findViewById(R.id.product_layout_image);
mtitletv.setText(name);
mdesrcriptiontv.setText(description);
mlocationtv.setText(location);
Picasso.get().load(image).placeholder(R.drawable.ic_baseline_cloud_download_24).into(mImagetv);
}
Sounds like you are either keeping references to the bitmap around. If that is not the case, but you are trying to keep references in memory, but reduce memory footprint with changing the sample size.
Sampling size can be thought of as this: If you have a 1000x1000 image by 8 bits per pixel..
You have a 1,000,000 bytes of image loaded into memory. Lets say you only needed a thumbnail of 100x100. You could then change the sampling size to 10, and it would read every 10th pixel from the file, building a newer / smaller memory footprint image. This would then Go from 1,000,000 bytes to 10,000 bytes.
Try the answer on this SO question..
Strange OutOfMemory issue while loading an image to a Bitmap object
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);
I am still fighting with a fluent recycler view that loads images without blocking the ui thread too much.
The problem is in the word "recycle" itself.
In my app I have a long list with mp3 files that, ofc, all have different names, different artists and different album covers.
However, they all DO use the same layout.
But can I now recycle the view or cant I?
Since loading the album cover right (also cropping it) took the most resources, I have decided to NOT recycle views with an album cover and ONLY recycle those who have no album cover, like so:
private async Task SetContentAsync(PhotoViewHolder vh, int position)
{
string SongName = "";
string ArtistName = "";
Bitmap bitmap = null;
byte[] data = null;
try
{
reader.SetDataSource(mp3Obj[position].Mp3Uri);
}
catch { }
await Task.Run(() => // cause problems with the reload
{
SongName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyTitle);
ArtistName = reader.ExtractMetadata(MediaMetadataRetriever.MetadataKeyArtist);
data = reader.GetEmbeddedPicture();
if (data != null)
{
try
{
bitmap = BitmapFactory.DecodeByteArray(data, 0, data.Length);
}
catch { }
}
});
((Activity)ctx).RunOnUiThread(() =>
{
vh.SongName.SetTypeface(tf, TypefaceStyle.Normal);
vh.AristName.SetTypeface(tf, TypefaceStyle.Normal);
vh.SongName.Text = SongName;
vh.AristName.Text = ArtistName;
try
{
if (bitmap != null)
{
vh.IsRecyclable = false; // MOST IMPORTANT THING TO DO!
ConvertBitmapToBackground(bitmap, vh, false); // Set As Backgorund, blurry and black ( just sets the variable)
CutImageIntoForm(bitmap, vh); // Set as the musical note button
}
else // because recycler items inherit their shit and if it is altered it just shows views were there shouldnt be any ...
{
vh.IsRecyclable = true;
// vh.CoverArt.SetImageResource(Resource.Drawable.btn_musicalnote);
// ConvertBitmapToBackground(bitmap, vh, true); // Set As Backgorund, blurry and black ( just sets the variable)
}
}
catch { }
});
}
Notice how I say "vh.IsRecyclable = ..." depending on whether there is an album cover or not?
This was the solution with the least amount of lags and works when only a few views include an album cover art. However, when the user has all songs with album covers the recycler view becomes extremely slow.
Another issue I am having is that sometimes, when lag occurs, the views double or even tripple. The still lead to the right file, but they all have the same song name for instance.
So what is best practice?
When can I recycle a view and when not?
How can I speed up the recycler view?
Thanks a lot for any answer!
How to display image from sql database to listview in android xamarin using webservices and json?
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = objList[position];
if (convertView == null)
{
convertView = objActivity.LayoutInflater.Inflate(Resource.Layout.ContListViewHospName, null);
}
convertView.FindViewById<TextView>(Resource.Id.tvHospID).Text = item.HospID;
convertView.FindViewById<TextView>(Resource.Id.tvHospName).Text = item.HospName;
byte[] img = (byte[])item.HospLogo;
Bitmap bitmap = BitmapFactory.DecodeByteArray(item.HospLogo, 0, item.HospLogo.Length);
convertView.FindViewById<ImageView>(Resource.Id.imgLogo).SetImageBitmap(bitmap);
return convertView;
}
i store binary value in one string variable then i use json to transfer values to my cs file in my android project
Your store binary value in one string should looks like this: "iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFUeJzsvfd33EiW7/mJgEtHb0WKFGWqSuW96epqM9P9+s30mZ/2j33n7O7Zt/Nme8zr6emu6i5fk........"
That is base64 bytes. You can not just use (byte[]) to convert the string to byte[]:
you need to use System.Convert.FromBase64String() function.
//The string is download form server in the json file
string myBytes = "iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAABHNCSVQICAgIfAhkiAAAIABJREFUeJzsvfd33EiW7/mJgEtHb0WKFGWqS........"
byte[] decByte3 = System.Convert.FromBase64String(myBytes);
And then convert the bytes to image:
public Bitmap Bytes2Bimap(byte[] b)
{
if (b.Length != 0)
{
return BitmapFactory.DecodeByteArray(b, 0, b.Length);
}
else
{
return null;
}
}
and convert the bitmap to drawable :
Bitmap myIcon = Bytes2Bimap(decByte3);
Drawable myIconD = new BitmapDrawable(myIcon);
imageView1.Background = myIconD;
May be your image is too big try to scale it, like here
Also make sure you have set proper dimension in your layout like width and height.
I am new to Android, I am developing an app, where in I search the youtube using the
....
YouTubeService service = new YouTubeService('blah','blah')
....
VideoFeed videoFeed = service.query(query, VideoFeed.class);
List<VideoEntry> videos = videoFeed.getEntries();
YouTubeMediaGroup mediaGroup = videoEntry.getMediaGroup();
String webPlayerUrl = mediaGroup.getPlayer().getUrl();
......
ytv.setWebPlayerUrl(webPlayerUrl);
.....
List<String> thumbnails = new LinkedList<String>();
for (MediaThumbnail mediaThumbnail : mediaGroup.getThumbnails()) {
thumbnails.add(mediaThumbnail.getUrl());
}
....
In the Adapter, I used this
mWebView.loadUrl(torvideo.getWebPlayerUrl());
But I get a full screen youtube image in the webview and a scroll able list of similar videos.
However What I want is a thumbnail which looks similar to youtube search result (Small Image, title of the video and few more details.
Can you please suggest me, which view or a sample code, so that I can use the thumbnails list I got it from mediagroup object to display in my app?
Edit/Update:
I have used
public class ResultViewAdapter extends BaseAdapter {
........
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if (row == null) {
final LayoutInflater li = (LayoutInflater) myContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(R.layout.activity_result_list, null);
}
TORYouTubeVideo torvideo = (TORYouTubeVideo) getItem(position);
TextView textView = (TextView) row.findViewById(R.id.textView1);
textView.setText(torvideo.getVideoTitle());
InputStream is = (InputStream) new URL(torvideo.getThumbnails().get(0)).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
ImageView imageView = (ImageView) row.findViewById(R.id.imageView1);
imageView.setImageDrawable(d);
return row;
}
But still I cannot see the images in my list view and Only see an empty scrollable list
Thanks
Answering my question again!!
Moved this part
InputStream is = (InputStream) new URL(torvideo.getThumbnails().get(0)).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
To the same async task where my youtube query is happening and I am able to see the image now!
(It was the issue with mainThread)
Looks like long way to go with Android!! :P
Thanks
I have 20 URL of different images. I need to download the 20 images from the URL and display it in Grid view. For me its taking much time to download the image content. Following is the code i'm using in Image Adapter class.
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, 200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(1, 1, 1,0);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageDrawable(GetDrawableImage(url));
return imageView;
}
private Drawable GetDrawableImage(String zurlP)
{ InputStream InputStreamL = null;
Drawable DrawableImageL = null;
try {
InputStreamL = (InputStream) new URL(zurlP).getContent();
DrawableImageL = Drawable.createFromStream(InputStreamL, "src");
} catch (MalformedURLException e) {
} catch (IOException e) {
}
return DrawableImageL;
}
Is there any easiest way(Less Time Consuming) to perform the same task?
Yes.., You can use Asynctask or Painless threading to load large images from server. And Cache the Images once you download. You can use [Fedor lazylist] for that (https://github.com/thest1/LazyList)
Various possibilities.
Multi Threading
Cacheing
Pain less threading
Large bitmaps loading
Or you can simply go with thumb nails. Means get thumb nails from server instead of bit images. Loading will be effective
You need to download images in other thread. You can use image loader.