Why Android is storing dynamic views in RAM? - android

Question may seem weird but I ran in an issue with Android app. I am creating views for my Android app dynamically using layout inflater and the view contains images. Most images are less than 800kb. So when I open the app, it starts using tons of RAM and when I switch to another activity, it adds more ram which contains images too. When I exit the activity and come back to the first activity it is not cleaning the RAM. I cannot add my actual code here because of the company policy but here is the snippet of what I am doing,
I have two activities HomeActivity and DisplayActivity. In home activity I have empty scrollview. I am making db query an pulling information. Using layout inflater,
for (DataModel d : dm) {
JSONObject dataJson = new JSONObject(d.getData());
View headerCard = LayoutInflater.from(HomeActivity.this).inflate(R.layout.head_card, null);
ImageView cardHeadImage = (ImageView) headerCard.findViewById(R.id.head_card_header_image);
TextView cardNote = (TextView) headerCard.findViewById(R.id.head_card_note);
String imageLink = dataJson.getJSONObject("data").getString("article_image");
String note = dataJson.getJSONObject("data").getString("article_title");
imageLoader.displayImage(h.getMediaURL() + imageLink, cardHeadImage);
cardNote.setText(note);
scrollViewChild.addView(headerCard);
}
So when I don't add images, it is using less RAM. I have cached images. So my question is that is there anything possible to clear RAM after view is generated and placed in display? I can provide more information if needed. But basically this is how my both activities are running.
The imageLoader works in three steps. 1) Check for cached image. 2) If image is not cached than download image and cache it. 3) Display image in imageview. 2nd step will be skipped most time as images are mostly available from cache.
Thanks. :D

Related

Expansion Android Apk working very slow whenever downloading first time

Currently, I am using this plugin
https://github.com/erobertson42/cordova-plugin-xapkreader/tree/cordova-9
I am using this path to show the image -
'content://com.x.x/main_expansion/assets/dummy.png';
and to make image path safe I am using domSanitizer.bypassSecurityTrustUrl method
getImg(img) {
img = this.domSanitizer.bypassSecurityTrustUrl(img);
return img;
}
Whenever I am using my app, it is working very slow but I am going one by one on the screen throughout the app first time it stucks on every screen approx 40 to 60seconds but after taking sometime it will work normally. If anybody has any suggestion or concern, please share

How to best load images from URL in Android ListView

So I have been struggling with the best way to load images in a ListView in Android for a while.
The images come from a server, so can take some time to load. From what I understand there are only 2 ways to implement this:
1 - Load the images on the main thread - This leads to have the correct images display immediately when the view displays and scrolls, but gives poor scrolling performance and can lead to the app hanging and crashing.
2 - Load the images in an AsyncTask. This means the images will be blank when the list display or scroll, but eventually display. Because of caching done by the list, you can also get the wrong image for an item. But this gives good performance and scrolling, and does not hang/crash.
Seems like neither solution works correctly. There must be a solution that works?? I have seen other posts like this, but the answer seems to always be 1 or 2, but neither is a good solution...
My code for the list adapter is below.
The HttpGetImageAction.fetchImage() method either executes an async task, or fetches the image on the main thread depending on a flag I set. I also cache the images locally and on disk once they have been loaded, so the issue mainly occur the first time (but the cache is only for 100 images, and the list has 1000s)
public class ImageListAdapter extends ArrayAdapter<WebMediumConfig> {
Activity activity;
public ImageListAdapter(Activity activity, int resourceId, List<WebMediumConfig> items) {
super(activity, resourceId, items);
this.activity = activity;
}
class ImageListViewHolder {
ImageView imageView;
TextView nameView;
TextView descriptionView;
TextView statView;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageListViewHolder holder = null;
WebMediumConfig config = getItem(position);
LayoutInflater mInflater = (LayoutInflater)this.activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.image_list, null);
holder = new ImageListViewHolder();
holder.imageView = (ImageView)convertView.findViewById(R.id.imageView);
holder.nameView = (TextView) convertView.findViewById(R.id.nameView);
holder.descriptionView = (TextView)convertView.findViewById(R.id.descriptionView);
holder.statView = (TextView)convertView.findViewById(R.id.statView);
convertView.setTag(holder);
} else {
holder = (ImageListViewHolder) convertView.getTag();
}
holder.nameView.setText(Utils.stripTags(config.name));
holder.descriptionView.setText(Utils.stripTags(config.description));
holder.statView.setText(config.stats());
if (MainActivity.showImages) {
HttpGetImageAction.fetchImage(this.activity, config.avatar, holder.imageView);
} else {
holder.imageView.setVisibility(View.GONE);
}
return convertView;
}
}
You should never load images on the main thread. Any network calls should be done asynchronously and should not be done on the main thread. Your images might load quickly (on the main thread) because you may have a good internet connection, have small images and/or have few images. But imagine what would happen if someone using your app has a slower internet and then one day your list grows to hundreds!
The approach below is a well accepted practice for loading scrollview content
a) load your text content as you load the scrollview. Again the loading should be done async but you can show a loading view until the download completes
b) Show image
placeholders while the image loads on each cell
c) Load the images
asynchronously
Using a library such as Picasso would help immensely because there is a lot of boilerplate code which you'd need to handle otherwise such as
cancelling image download when a cell is reused and
starting a new download for a reused cell
caching
retrying a failed download
Hope this helps.
Use Glide [https://github.com/bumptech/glide] or Picasso [http://square.github.io/picasso/] - both libraries are very similar, and easy to use, have caching, work in background, allow placeholders ets.
Usage is as simple as:
Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);
Simple Solution: Glide.
Glide is a fast and efficient open source media management and image
loading framework for Android that wraps media decoding, memory and
disk caching, and resource pooling into a simple and easy to use
interface. Glide supports fetching, decoding, and displaying video
stills, images, and animated GIFs.
You can load the image like:
GlideApp.with(context)
.load("http://via.placeholder.com/300.png")
.into(imageView);
Refer for more info:
https://guides.codepath.com/android/Displaying-Images-with-the-Glide-Library
https://github.com/bumptech/glide
Use Glide library.. Its recommended by Google.
Step 1:
Use latest Glide Version 4 dependency (https://github.com/bumptech/glide)
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
Step 2:
Glide.with(MainActivity.this)
.load(url)
.apply(new RequestOptions().placeholder(R.drawable.placeholder).error(R.drawable.error_image))//this line optional - you can skip this line
.into(imageview);
use picasso or Glide Library
What these library do , is that they image url from u and download them and save it in cache so that whenever you open the same image another time it will load faster and it prevents the usage of the network
Picasso
http://square.github.io/picasso/
Glide
https://github.com/bumptech/glide
You can try UnivarsalImageLoader which is quite Fast and Optimised.
It supports Multithread image loading (async or sync) and high level of customization.
https://github.com/nostra13/Android-Universal-Image-Loader
Here's how I do it
First I always create the RecyclerView.ViewHolder to which I pass a Func<int, Bitmap> image_provider (or you can pass some sort of lamda?) which when called will retrieve the image for a specific Id, if it can't it will show the default loading image
Everything is stored in a fragment (which I call a DataFragment) which has retainstate set to true.
First load a list of json objects that tell me which images I must show, this happens inside the data fragment so it will go on if there is a configuration change
I send that info to the adapter using a method like SetItems(MyImages)
Then I start a new thread that will load the images (while allowing the user to work)
I do this with the TPL library, the closest approximation for Android is Anko Async but you can also do it with AsyncTask, the problem is that I send a lot of messages to the main thread, so to do it with AsyncTask you have to give it a handler to the main thread which will send messages.
In the thread I loop through all the images I have to download, and download them and send a message to the DataFragment which sends it to the currently attached Activity which triggers the NotifyItemChanged method in the adapter
The adapter on creation receives a Func<int, Bitmap> image_provider which it invokes and retrieves the image from memory
I know it sounds a bit messy, so if you want code examples I can give them , but they are in C#
In your app level gradle implement below repository:
implementation 'com.squareup.picasso:picasso:2.5.2'
Put below line where you want to load image
Picasso.with(getApplicationContext()).load(config.avatar).into(imageview);
just use Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView); or
Glide.with(getApplicationContext()).load("image_url").asBitmap().centerCrop().into(new BitmapImageViewTarget(imageView)
in adapter like any view and done no extra efforts required

Android, Xamarin: Load Pictures Into Recycle Viewer While Scrolling

Have you ever been going through apps like 9gag, Instagram or Facebook? You notice, that while scrolling the pictures load into the recviewer. They sort of come in one by one while you can still use the app.
I have implemented my own custom recviewer and am stuck right here:
pictures = KumulosHelper.Pictures.getNewestXPhotosFromUserInRange
(strUsername, "6", startNumberOfTask.ToString(), "1");
foreach (var picture in pictures)
{
startNumberOfTask++;
var metrics = Resources.DisplayMetrics;
lstData.Add(new DataForProfile()
{
imageId = startNumberOfTask,
img = (Bitmap.CreateScaledBitmap
(KumulosGeneral.DecodePhotoFromBase64(picture.photo),
metrics.WidthPixels, metrics.WidthPixels, true)),
description = picture.taskId.ToString()
});
}
Where I type in "6" is where I get 6 pictures to load into my recycle viewer form the server. I can type in 10 or 20 and it continues loading those pictures. So, I could probably set up a "reachedbottomevent" to continue loading new pictures when the viewer reached the end. But that would mean that the user has to wait everytime he or she reached the bottom of the matrix. This is pretty annoying. Also, the whole activity wont start untill all pictures are fully loaded.
How do I get my recview to behave like the afforementioned apps above? Some sort of "smart" loading the pictures?
Thank you for the input!
Try using the Picasso library which is very reliable and easy to use. It also loads pictures in a background thread.
https://www.nuget.org/packages/Square.Picasso/
Also, the whole activity won't start until all pictures are fully loaded.
In order not to block your UI thread try using a BackgroundWorker or a Task.
At last, if you want to load a new batch of images before the user reaches the bottom of your list, then change your logic to trigger the call for a new batch for example when the user scrolls half the table.

Images randomly break in PhoneGap/WebView on Android 4.4

I am experiencing a strange bug in PhoneGap on Android 4.4, for which I couldn't find any solution online. In my app, I am loading a lot of different images from a remote server, and as the user navigates back and forth, new images are loaded on each page (4 at a time, to be specific, through jQuery-generated html). After having navigated back and forth for a little while, some images will randomly not show up and instead show the typical "broken image" icon.
Now, here comes the strange part: I have been following the instructions at jQuery/JavaScript to replace broken images and done a few tests of my own. In conclusion, the naturalWidth and naturalHeight parameters report the right sizes of the images, and complete reports true for all images. Therefore, the solutions mentioned in the above SO thread don't work at all. Changing the image src doesn't help, either with or without a setTimeout (I tried adding the current timestamp as a parameter to the image path as well).
Did anyone else encounter this issue at all, or am I going crazy here? :)
EDIT: By the way, no error is ever reported. Therefore, no error handler is called when loading the image, making it useless to solve the problem with the already suggested methods (see the link above).
This is how i handle error images,
<img src="images/imageName.jpg" onError="onErrorFunc(this);" alt=" " />
function onErrorFunc(elem){
var imgUrl = "https://alternative-image";
elem.onerror = function (){
elem.src='images/noimage.jpg';
}
elem.src=imgUrl;
}
Hope it helps!

The method setImageDrawable(getResources().getDrawable(XX)) doesn't display the good image

i succeed in using this code in a new project, but, when copying it in my actual code, the image displayed is not the good one
everything is well made (image is in the folder drawable, every data well declared, ...)
image begin with "phoXX", where XX is an integer (between 0 and 62)
i have an imageview (named imageView1) and a TextView (to debug, named textView1) in which i display the ID (which one is good when checking in R.java...)
here is my code :
private Context mContext;
ImageView imageC=(ImageView)findViewById(R.id.imageView1);
TextView Tex=(TextView)findViewById(R.id.textView1);
Drawable drawableX = this.getResources().getDrawable(android.R.drawable.ic_dialog_alert);
Random random_monster = new Random();
int lerand = random_monster.nextInt(62);
int id = mContext.getResources().getIdentifier("drawable/pho"+lerand, "drawable",mContext.getPackageName());
if (id>0)
{
drawableX = getResources().getDrawable(id);
}
imageC.setImageDrawable(drawableX);
Tex.setText(Integer.toString(lerand)+":"+id);
So, as i say, an image is displayed, a number is displayed, but pho29 for exemple show the image named pho48 (and pho48 doesn't display pho29 if you ask)
ID is 2130837535, which is what appears in R.java :
public static final int pho29=0x7f02001f;
pho48 is :
public static final int pho48=0x7f020034;
for some number, the image displayed is the good one, for other, the image is not the good one (and it's always the same image displayed for the same number....i mean for pho29, it's ALWAYS pho48 which is displayed, in every one of my activity)
I really don't understand what i miss...Thx all for any kind of help
Edit : below some matching (on the left side the number which should be displayed, on the right the number displayed)
2->6
17->32
19->34
24->41
43->43
51->51
36->55
37->56
38->57
56->56
59->59
61->61
As you can see, 56 is displayed by 56 AND 37....
If the same code and set of image resources work fine in one project and not in another, you should consider whether the compiled resources in the broken project are actually correct. I have found when using the automatic build feature in Eclipse that the resources don't get recompiled when I expect them to. For instance if the last thing I did before deploying an app was to change the resources. Saving a code file change seems to drive the build system harder.
You should try doing a clean then a rebuild. In Eclipse, on the Project menu choose "Clean..." and pick your project (or let it clean them all). Eclipse will then do a full rebuild. Or on the command line run "ant clean" followed by "ant debug".
Also you are using this line:
int id = mContext.getResources().getIdentifier("drawable/pho"+lerand, "drawable",mContext.getPackageName());
Here is the API spec:
public int getIdentifier (String name, String defType, String defPackage)
You don't need to specify the type in the name field, because you are specifying it in the defType field. I don't think it will solve your problem, but this should work at least as well:
int id = mContext.getResources().getIdentifier("pho"+lerand, "drawable",mContext.getPackageName());
Try to put the imageview without source in its definition, sometimes I have the problem when an imageview has source set in xml, changing its drawable in runtime not work, the first image is always visible

Categories

Resources