I am using ImageView inside my custom Adapter class. The problem is my Adapter has 2 image views inside and I am using a "placeholder image" as a default image on them but when I try to populate my RecyclerView and setImageResource() using Adapter's ViewHolder it simply goes behind the default "placeholder image" instead of overwriting it. I am quite new to both Java and Android App Development so I don't know if the setImageResource() works different with Adapters.
Here's my code:
public void onBindViewHolder(#NonNull ProductAdapter.ViewHolder holder, int position) {
holder.itemView.setTag(product.get(position));
holder.tvTitle.setText(product.get(position).getTitle());
holder.tvDescription.setText(product.get(position).getDescription());
//PROBLEM STARTS HERE
//Set Status (getSale() returns bool)
switch (product.get(position).getSale()?"sold":"available"){
case "sold":
holder.ivStatus.setImageResource(R.drawable.sold);
break;
case "available":
holder.ivStatus.setImageResource(R.drawable.available);
break;
}
//Set Product Image
switch (product.get(position).getType()){
case "Laptop":
holder.ivProduct.setImageResource(R.drawable.laptop);
break;
case "LCD":
holder.ivProduct.setImageResource(R.drawable.screen);
break;
case "USB":
holder.ivProduct.setImageResource(R.drawable.memory);
break;
case "Hard Disk":
holder.ivProduct.setImageResource(R.drawable.hdd);
break;
}
}
In Both cases the switch-case works correctly and picks the right image resource but it simply places the image Resource behind placeholder image. how do I just overwrite the default image?
The reason you see both images because you set both background and foreground images on the ImageView
To solve this remove android:foreground from both ImageViews and leave the placeholder in app:srcCompat
So your ImageView should look like:
<ImageView
android:id="#+id/ivStatus"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
app:srcCompat="#drawable/placeholder" />
Do you know good practices to avoid memory leaks ?
I am currently working on an app which has few memory leaks, that I struggle to fix, mainly because I don't know the habits that I need to take to be able to avoid them.
For instance, at the moment I get this issue
Fatal Exception: java.lang.OutOfMemoryError
Failed to allocate a 1627572 byte allocation with 1293760 free bytes and 1263KB until OOM
Raw Text
dalvik.system.VMRuntime.newNonMovableArray (VMRuntime.java)
android.view.LayoutInflater.inflate (LayoutInflater.java:429)
com.XX.Dialog.PopupDialog.onCreateView (PopupDialog.java:50)
Which comes from the inflater.inflate(R.layout.dialog_popup, container, false); in the onCreateView !
Here is the DialogFragment concerned :
public final class PopupDialog extends DialogFragment {
public PopupDialog()
{
}
#Override
public void onSaveInstanceState(Bundle outState) {
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
View view = inflater.inflate(R.layout.dialog_popup, container, false);
return view;
}
The layout is quite long, but basically it got 5 ImageViews . Here is an sample :
<ImageView
android:layout_width="match_parent"
android:layout_height="80dp"
android:id="#+id/popup_top_bg_iv"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="false"
android:layout_alignParentStart="false"
android:src="#drawable/popup_top_bg"
android:scaleType="fitXY"
android:background="#color/transparent" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/popup_top_bg_iv"
android:background="#ffffff"
android:layout_alignBottom="#+id/popup_bottom_ll" />
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/popup_top_iv"
android:src="#drawable/popup_0_top"
android:scaleType="fitCenter"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" />
....
So .... I was wondering if you know :
1. What could lead to this memory leak error from this dialogFragment ?
2. Any good practices in android to avoid memory leaks ?
For instance for that file, should I call
imageView.setImageDrawable(null);
On every Imageview when the popup is closed / Activity is closed (R.drawable.* ) ? Or just when I load an image from an URL (with Glide for instance) dynamically ?
Should I always resize an image to the dimension of my Imageview ?
What exactly do I need to clean after the Fragment/Activity is closed ?
What do you think ?
After a bit of digging I came with these solutions :
you can use Leak canary to track your memory leak (https://github.com/square/leakcanary)
Or the Memory monitor of Android studio : https://developer.android.com/studio/profile/am-memory.html
Use a library to load your images such as Picasso or Glide. Personally I prefer Glide.
https://medium.com/#multidots/glide-vs-picasso-930eed42b81d
Never keep references of Activity of context in static. NEVER!
Otherwise your references might still be there even if you need it.
Avoid keeping references of ImageViews. Recycle / Clear the bitmap inside when your destroy the view.
If you need to have a reference of the context, please use context.getApplicationContext();
Don't use context.getApplicationContext(); for LayoutInflater.from(context); but directly the context.
(in case if you need to inflate a view or need a context for something).
If you use the context.getApplicationContext() it can lead to some design issues if you create views dynamically.
If you get some OutOfMemory error, think to compress your images ! It actually saves me lot of OutOfMemory error. You can use https://tinypng.com/.
Don't put by default your images into the folder drawable-xhdpi but drawable-mdpi instead as drawable-mdpi is the default one.
So for my issue I just need to compress the images and put them back in the drawable-mdpi folder ! All good now !
I am using fersco library for loading local image. Initially i am displaying placeholder image in each item.Once the image is downloaded then i am storing that image in to local path and then load image via setImageUri function. If i am scrolling fast at the time of downloading image it display different image and re-appearing some time keep on changing if i am stop scrolling.
My SimpleDraweeView :
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/fake_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="center|center_horizontal|center_vertical"
android:adjustViewBounds="true"
android:contentDescription="#string/app_name"
android:scaleType="centerInside" />
My Adapter Code is :
GenericDraweeHierarchy hierarchy = setHierarchyForDraweeView(mImageView, 300);
hierarchy.setFailureImage(mContext.getResources().getDrawable(R.drawable.broken_image_black));
mSimpleDraweeView.setImageURI(Uri.fromFile(new File(mPath/local path/)));
SetHierarchyForDraweeView Function :
private GenericDraweeHierarchy setHierarchyForDraweeView(SimpleDraweeView draweeView, int duration) {
if (draweeView != null) {
if (draweeView.getHierarchy() == null) {
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(mContext.getResources());
GenericDraweeHierarchy hierarchy = builder
.setFadeDuration(duration)
.setPlaceholderImage(new AsyncColorDrawable(mContext.getResources()))
.setFailureImage(mContext.getResources().getDrawable(R.drawable.broken_image_black))
.build();
draweeView.setHierarchy(hierarchy);
} else {
GenericDraweeHierarchy hierarchy = draweeView.getHierarchy();
hierarchy.setFadeDuration(duration);
return hierarchy;
}
}
return null;
}
AsyncColorDrawable Class :
private class AsyncColorDrawable extends ColorDrawable {
public AsyncColorDrawable(Resources res) {
super(res.getColor(R.color.RED));
}
}
I am doing anything wrong ?
I see several things that should be fixed, but none of which would explain incorrect loading. I will be able to help, but I'll need the logcat logs as explained here. Also, there is one thing I don't fully understand. From your description it seems that you are downloading your images manually, saving them to disk and when they are downloaded you set the Uri. Why not using Fresco to automatically download and disk-cache images for you? Can you provide this piece of code as well, because the issue might very well be there.
Things that should be fixed:
adjustViewBounds and scaleType attributtes are not supported by SimpleDraweeView. Drawee operates on several images at once (placeholder, failure image, actual image, etc.) Each can have its own scale type so you need to use Drawee atrributes as explained here.
If you are inflating your view from XML, draweeView.getHierarchy should never be null. You would have a NullPointerException anyway because you are not returning hierarchy from that if-branch. So, you can specify your failure image via XML too, no need to do that programmatically. Same for the fade duration if you always use the same value.
The following error occurs when I attempt to inflate a layout within a ListView:
requestLayout() improperly called by android.widget.TextView{...} during layout: running second layout pass
I am attempting to inflate a layout within a ListView as follows:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) musicActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_item, parent, false);
...
}else{...}
}
The layout being inflated can look as simple as the following, and will still produce the error
<TextView
android:id="#+id/txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="#dimen/txt_size"/>
I have looked into similar questions, and no solutions found seem to work Question 1, Question 2, Question 3.
Does anyone know what causes this type of error? Any troubleshooting advice? For more context, this ListView is displayed within a Fragment within a ViewPager
UPDATE
Here is the full XML Layout (minus a bunch of attributes), that still results in the problem
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
Based on this, I would think the XML itself is not a problem, unless it has to do with the fact that I am using a ViewPager and Fragments
This issue seems to be a bug in the android implementation, please see: https://code.google.com/p/android/issues/detail?id=75516
Activating the fast scroll feature of a ListView in your code via ListView.setFastScrollEnabled(true) will trigger this bug and you'll start seeing the
requestLayout() improperly called by android.widget.TextView{...}
during layout: running second layout pass
message in your console.
This bug must have been introduced in one of the KitKat (4.4.x) updates, as I've not seen it with the initial KitKat (4.4.0) release. Apart from the ugly console spamming with the debug message from above, there seem to be no other impacts (maybe performance in some cases, which I haven't tested).
Cheers
PS: it's not the first time that the fast scroll feature is bugged, e.g. https://code.google.com/p/android/issues/detail?id=63545, 63545 was fixed in KitKat 4.4.3 but 75516 poped up thereafter --> seems to be a vexed subject for google ;-)
EDIT May 12 2015:
I updated my Nexus 7 to Android 5.1 some minutes ago (was Running 5.0 before) and stopped seeing this issue in this new version. As the appearance of the FastScroll indicator also changed in 5.1, I assume that google fixed this issue or at least commented out those ugly lines that spammed the console...
75516 & 82461 are still 'unresolved', but I guess that those refer to the same issue, that's now resolved in 5.1.
The problem is that while the method getView() of your adapter is displaying your layout some other code is trying to access this view to display it, resulting in a collision.
Note that some methods, that maybe you don't take care of (like setScale(), setTypeFace()) indeed call requestLayout(), so it would be interesting what you are doing after your inflate statement.
For me this issue was occurring upon a setLayoutParams() call. The solution was posting a runnable on the looper:
// java
imageView.post(new Runnable() {
#Override public void run() {
imageView.setLayoutParams(params);
}
});
// kotlin
post(Runnable { imageView.setLayoutParams(params) })
I fixed this issue by disabling fastScroll on the ListView in the XML.
<ListView
android:id="#+id/mListview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:fastScrollEnabled="false"
/>
In my case (Samsung Galaxy S4, API 21) this happened in ListView with EditTexts. I have a listener for field validation. Something like:
edit.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
error.setVisibility(View.INVISIBLE);
error.setText("");
} else {
String s = edit.getText().toString();
if (s.isEmpty()) {
error.setText("Error 1");
} else if (s.length() < 2 || s.length() > 100) {
error.setText("Error 2");
}
error.setVisibility(View.VISIBLE);
}
}
});
After settinging focus in one of these EditTexts an above check is called. After that a TextView will change (the TextView contains an error message and lies over the EditText).
Setting focus to the second or the third EditText led to permanent request of the first EditText and return to current. An applications runs in infinite loop of requests (focus edittext 1, unfocus edittext 1, focus 3, unfocus 3, focus 1, etc).
I tried to set listView.setFastScrollEnabled(false). Also I tried a requestLayout() of some elements like in https://github.com/sephiroth74/HorizontalVariableListView/issues/93 with no chances.
Currently I made that TextView of fixed width and height in XML:
<TextView
android:id="#+id/error"
android:layout_width="match_parent" (or "200dp", but not "wrap_content")
android:layout_height="20dp"
.../>
After some experiments I noticed that a height of 20dp can be replaced with "wrap_content". But if a text is too long that divides into 2 lines, the application again catches in the infinite loop. So, android:singleLine="true" will help. It is deprecated, but amazingly android:maxLines="1" with android:lines="1" don't help as they again request layout.
Eventually we have:
<TextView
android:id="#+id/error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="#f00"
android:textSize="20sp"
tools:text="Error message"/>
That's not a good solution, but at least it breaks the infinite loop.
This might happen if you are using some 3rd party extension of ListView. Replace that with standard ListView and check if it still throws the error.
I had similar problem. Please check Android layout: running second layout pass and my answer.
I had the same issue with Kitkat 4.4.4 on Motorola X with Genymotion. In my case the list item is a simple CheckedTextView and the error occurred in AppCompatCheckedTextView.
As a normal implementation I inflated the item from XML layout file like below:
if (convertView == null) {
convertView = inflater.inflate(R.layout.checkable_list_entry, parent, false);
}
After some trying I found out that this has something to do with XML inflation. I don't know the root cause, but as a solution I decided to inflate the list item by code and set all the properties by code too.
It ended up like this:
CheckedTextView view;
if (convertView == null) {
view = new CheckedTextView(parent.getContext());
view.setMinHeight(getResources().getDimensionPixelSize(R.dimen.default_touch_height));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
view.setTextAppearance(R.style.SectionEntry);
} else {
view.setTextAppearance(parent.getContext(), R.style.SectionEntry);
}
view.setBackgroundResource(R.drawable.form_element);
view.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.WRAP_CONTENT));
} else {
view = (CheckedTextView) convertView;
}
I had a problem with the same warning log :
requestLayout() improperly called by android.support.v7.widget.AppCompatTextView {...} during layout: running second layout pass
I was working with recylcerview and going to update it with new data.
The only solution that worked for me is as below :
Step(1). Remove current data :
public void removeAll() {
items.clear(); //clear list
notifyDataSetChanged();
}
Step(2). When you want to populate the recyclerview with new data, first set a new LayoutManager to recyclerview again:
private void initRecycleView() {
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false));
}
Step(3). Update the recyclerview with new data. for example :
public void refreshData(List newItems) {
this.items = newItems;
notifyItemRangeChanged(0, items.size());
}
Try taking off the textSize from the xml and setting it in Java code. I think that's causing it to be laid out twice.
In my case this warning prevented a button from showing up in API 21 devices. The button visibility was previously set to GONE.
The only workaround I got it was setting to INVISIBLE instead of GONE for API 21. It wasn't a real solution but it was acceptable for me.
I only post this because it can be useful from somebody.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
theButton.setVisibility(View.INVISIBLE);
}
else {
theButton.setVisibility(View.GONE);
}
Sometimes you maybe already fixed the issue but it still keeps same error, so you need to close visual studio then delete all bin and obj folders from your projects, then uninstall the app from the emulator. then walah!! everything will works fine
I solved the problem like this:
mHolder.txt_fword.setTextSize(22);
mHolder.txt_farth.setTextSize(22);
mHolder.txt_fdef.setTextSize(22);
mHolder.txt_fdef2.setTextSize(22);
mHolder.txt_frem.setTextSize(22);
//if (fdef2.get(pos).equals("")) mHolder.txt_fdef2.setVisibility(View.GONE);
//if (frem.get(pos).equals("")) mHolder.txt_frem.setVisibility(View.GONE);
issue is .setVisibility(View.GONE); , change to .setVisibility(View.VISIBLE);
I have problems with lagg when scrolling and space between listItems. If anybody could give me a hint on what's wrong with my code I would be really greatfull.
When my app starts I download all thumbnails from my server and save them like this:
FileOutputStream fos = openFileOutput(uniqueName, Context.MODE_PRIVATE);
fos.write(bytes);
fos.close();
All the images are 100px x 75px
ListItem:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:id="#+id/pic"
android:layout_width="100dp"
android:layout_height="75dp">
</ImageView>
</RelativeLayout>
I then load the images with asyncTask like this:
private Drawable d;
#Override
protected Integer doInBackground(String... arg0) {
File filePath = ctx.getFileStreamPath(fileName);
if (filePath.exists()) {
d = Drawable.createFromPath(filePath.toString());
return 1;
}
return 0;
}
#Override
protected void onPostExecute(Integer success) {
if (success == 1) {
listener.onCacheThumbCompleted(d);
}
}
Finally add the image to imageView in listItem:
public void onCacheThumbCompleted(Drawable drawable) {
iv.setImageDrawable(drawable);
}
But it's not smooth at all when scrolling. Also it seems that the image does not fill the imageView completely. It's a space between the listItems even if I set the dividerHeight to 0.
Same problem and he solved it by resizing his images, but do I need to resize/scale my images to fix my problems?
Smooth ListView can be quite complex on Android. The best example I've found is Shelves by Romain Guy. It features a lot of complex patterns and can be hard to digest but if you do digest everything you'll be a lot smarter when you come out on the other side :)
To list some of most important enhancements:
Lazy load of images
ViewHolder
Resizing of images
You could also search for these enhancement features and implement them yourself.
Try using LAZYLIST/ LAZY-LOADING if you have a lot of images.