I have a problem in my application Life Gallery. In this application, I have a fragment that displays the user's media directory in a gridView. Here is a screenshot :
As you can see, each directory is represented with an ImageView and a TextView, this latter containing the name of the directory. If you check the third line, you will see that the text of two TextView are empty...This is my bug. The elements of my gridview that present such a bug varies if I scroll or if rotate my phone...
Here is my layout for an element of the gridView :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_global"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="1dp" >
<ImageView
android:id="#+id/directory_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/content_description_album_imageview" />
<TextView
android:id="#+id/directory_text"
style="#style/Act_MyOwnLife_TextView_large"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/directory_image"
android:background="#color/black_transparent"
android:gravity="right"
android:paddingRight="4dp"
android:singleLine="true"
/>
</RelativeLayout>
And here is the code for my Adapter, focusing on the function getView:
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder viewHolder = null;
if (view == null) {
LayoutInflater inflater = this.activity.getLayoutInflater();
view = inflater.inflate(R.layout.fragment_directory_gridview, parent, false);
viewHolder = new ViewHolder();
viewHolder.relativeLayout = (RelativeLayout)view.findViewById(R.id.layout_global);
viewHolder.textViewDirectory = (TextView) view.findViewById(R.id.directory_text);
viewHolder.imageViewDirectory = (ImageView) view.findViewById(R.id.directory_image);
view.setTag(R.id.viewHolder, viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag(R.id.viewHolder);
}
viewHolder.relativeLayout.setLayoutParams(this.viewFragmentDirectory.layoutParams);
viewHolder.imageViewDirectory.setTag(position);
viewHolder.imageViewDirectory.setImageBitmap(null);
viewHolder.position = position;
ModelDirectoryAndMedia directoryAndImage =this.directoriesAndMedias.get(position);
viewHolder.textViewDirectory.setText(directoryAndImage.directoryView);
ImageView imageView = viewHolder.imageViewDirectory;
// creation/retrieve the thumbnail with a thread
job = new Job(imageView,
directoryAndImage.media, Options.OPTIONS_THUMBNAIL,
position);
this.bitmapCreate.addJobThumbnail(job);
return view;
}
What I did to find the bug :
I check that my String was not empty when I call "viewHolder.textViewDirectory.setText(s);"
I try to check with hierarchyViewer, but I can not browse an element if the TextView is empty...I do not know why...
I remove the transparency of the background, remove the background property of the textView, I set "ImageView.setImageBitmap(null);" to check that it was not due to the ImageView...
But without success...the bug was still here...
After more test, I found the reason of the bug: it is due to this line of code in the getView method :
viewHolder.relativeLayout.setLayoutParams(this.viewFragmentDirectory.layoutParams);
I use this line to display the empty ImageView to the correct size. So that when the thumbnail is ready, the insertion in the ImageView will not change its size ( the settings of my LayoutParams is done with the size of my thumbnail )
Any idea ? any comments on my code ?
Thanks a lot !
Ok...The bug was due to the call to :
viewHolder.relativeLayout.setLayoutParams(this.viewFragmentDirectory.layoutParams);
But I do not understand why...anyway, I did this to ensure that my ImageView had the correct initial size to display the thumbnail, loaded by a thread.
So I found an other solution to set a minimum size to the ImageView even if they are empty :
viewHolder.imageView.setMinimumHeight(this.viewControlerAlbum.sizeThumbnail);
viewHolder.imageView.setMinimumWidth(this.viewControlerAlbum.sizeThumbnail);
My layout.xml file is a bit updated :
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="#string/content_description_album_imageview"
android:scaleType="centerCrop"
android:adjustViewBounds="true"/>
I added the adjustViewBounds attribute.
Related
I am currently working on a file sharing application. I created a GridView, where I would like to list the already downloaded files with a thumbnail. To achieve this, I use a custom adapter. It loads fine, everything is visible, seems perfect.
And the trick is the following: after the view is loaded, the getView method of my custom adapter is called on position 0 so many times, that it causes massive laggs, with about 12% CPU usage on my Xperia XZ Premium.
I already read answers about laggs in GridView, but in those cases it was caused by scrolling. In my case, no scroll is needed, currently there is only 1 item in the GridView, but it is still struggling.
While lagging, it also spams a message. This message can disappear, if I add the following line of code to my TextViews:
android:singleLine="true"
But this attribute is deprecated and doesn't solves the issue, only the message disappears.
The lagg is not present, when the view is empty.
The getView method of my adapter:
#Override
public View getView(int position, View convertView, #NonNull ViewGroup parent){
View listItem = convertView;
if(listItem==null){
listItem = LayoutInflater.from(getContext()).inflate(R.layout.downloaded_grid_item, parent, false);
}
final Downloaded current = getItem(position);
final ImageView thumbnail = (ImageView)listItem.findViewById(R.id.downloaded_grid_item_thumb);
final TextView name = (TextView)listItem.findViewById(R.id.downloaded_grid_item_name);
final TextView subtext = (TextView) listItem.findViewById(R.id.downloaded_grid_item_subtext);
thumbnail.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int width = thumbnail.getMeasuredWidth();
thumbnail.setLayoutParams(new LinearLayout.LayoutParams(width, width));
return true;
}
});
listItem.setTag(position);
thumbnail.setTag(position);
name.setTag(position);
subtext.setTag(position);
name.setText(current.getName());
subtext.setText(DateFormat.getDateInstance().format(new Date(current.getTime())));
thumbnail.setImageBitmap(ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(current.getPath()), 400, 400));
return listItem;
}
The GridView:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/downloaded_grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:layout_margin="10dp"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
The custom layout of the items:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/downloaded_grid_item"
android:background="#drawable/downloaded_grid_item_background"
android:orientation="vertical"
android:padding="4dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/downloaded_grid_item_thumb"
android:layout_width="match_parent"
android:layout_height="90dp"
android:src="#drawable/ic_menu_gallery"
android:scaleType="centerInside"/>
<TextView
android:id="#+id/downloaded_grid_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
tools:text="name"
android:ellipsize="end"
android:lines="1"/>
<TextView
android:id="#+id/downloaded_grid_item_subtext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="#style/TextAppearance.AppCompat.Small"
tools:text="download date"
android:ellipsize="end"
android:lines="1"/>
</LinearLayout>
And the message, spammed by the device:
W/StaticLayout: maxLineHeight should not be -1. maxLines:1 lineCount:1
After running your code in an emulator (Android 7), I did not manage to get the message about the maxLineHeight but I can confirm that there was no end of getView() being called.
The reason for this behavior is that each time getView() is executed you add a new OnPreDrawListener without ever removing it. Changing the ImageView's height forces a recalculation of how it is to be drawn. This causes the whole GridView to go through a new layout pass (measure - draw - layout). So getView() is called again (normally at least twice for position 0). Because you never remove a OnPreDrawListener they all will fire once more, only causing more and more work for the CPU without actually changing the value for the ImageView's height.
You need to remove the Listeners you add to a ViewTreeObserver as soon as you obtained the desired information. So you need to write
thumbnail.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
thumbnail.getViewTreeObserver().removeOnPreDrawListener(this);
int width = thumbnail.getMeasuredWidth();
thumbnail.setLayoutParams(new LinearLayout.LayoutParams(width, width));
return true;
}
});
I am new to android and I want to add a long list of textViews to a LinearLayout (about 200 textviews).
As you know adding large views to layout causes the Activity to freeze until all of textviews are added. I want to refresh the layout after each addview and show the new textview that is added to the layout. I have tested everything that came to my mind and I've searched all the web for answer and I know that I must use threads, but none of threads worked for me.
I have used ListView but it is too slow because it needs to make so many control invisible when they are out of view.
How can I force a refresh after each view?
Edit:
Here is the layout that is being inflated about 100 times:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:pixlui="http://schemas.android.com/apk/com.neopixl.pixlui"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp" >
<com.neopixl.pixlui.components.textview.TextView
android:id="#+id/itemTitle1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text=""
android:textColor="#58595b"
android:textSize="#dimen/details_title_font_size"
pixlui:typeface="font.ttf" />
<JustifiedTextView
android:id="#+id/itemText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textColor="#58595b"
android:textSize="#dimen/details_font_size"
android:lineSpacingMultiplier="2"/>
</LinearLayout>
And here is getView method of my BaseAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.rowitemview, null);
holder = new ViewHolder();
holder.title1 = (TextView) ((LinearLayout)convertView).getChildAt(0);
holder.text1 = (JustifiedTextView) ((LinearLayout)convertView).getChildAt(1);
holder.text1.SetTextAlign(Align.RIGHT);
holder.text1.setTypeface(font);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.title1.setText(getItem(position).getTitle());
holder.text1.setText(getItem(position).getDesc());
return convertView;
}
The problem with this ListView is that it is very laggy when scrolling up or down. I even tried lazy loading items, but it didn't work either.
You really need to refactor your code to not add 200 textviews.
What you can do is replace those 200 textviews with one listView. This adds and recycles child views dynamically. So even if you have 200 entries, the app will only occupy itself with what needs to be drawn on the screen.
See listview tutorial.
I'm having a slightly weird error here on my adapter.
The view the adapter is creating is a thumbnail on the left side and a table with a few rows. Each row have two textviews.
One of the textviews have the android:autoLink="web" property set and the listview have an onItemClickListener on it.
the problem is that every time a TextView auto-links it's content, next time its parent view is converted, it doesn't receive clicks from the onItemClickListener anymore.
Let me clarify with an example:
view1, view2, view3 and view4 are on the list view on the screen.
view2 have a link and it appears, and onClick the link opens.
the item click works normally for view1, view 3 and view4.
scroll the listview and view1 is converted to position5 and then view2 is converted to position6.
the item at position6 does not contain a link, but the onItemClick is also not fired for the position6 element.
the autolink feature of the textview is certainly changing something with my layout, but I don't know what. There must a property I can reset for every call to getView on my adapter, but which?
thanks for any help.
edit
let's see some code, it's pretty standard/good practices.
the getView from my adapter is:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Inflate a new layout if needed
if (convertView == null)
convertView = createNewView();
// Gets the item from my array
AGplus item = (AGplus) getItem(position);
// Gets the holder pointing to the views
Holder h = (Holder) convertView.getTag();
// That's a test version, I won't be using date.toString() later on
h.date.setText(new Date(item.getDate()).toString());
// This guys is giving me a headache,
// If it parses the link, I can't never click on this convertView anymore,
// event re-converting them for a text that does not contain links
h.txt.setText(item.getTitle());
// some image download stuff that doesn't matter for this code
return convertView;
}
that layouts used is a image and table and the amount of rows I inflate and insert on the table varies for each adapter. The table layout is a horizontal linear layout with a imageview and the table layout with some margin stuff and here is the row layout:
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#color/text" />
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:text=""
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#color/text" />
</TableRow>
if I completely remove the android:autoLink="web" I get all the clicks, but as stated before, once a view gets "auto-linked" and then I recycle that view, I can't get clicks on that view again.
edit
and here is the layout inflation:
private View createNewView() {
// Instantiate view
View v = getLayoutInflater().inflate(R.layout.expandable_child_view, null);
TableLayout table = (TableLayout) v.findViewById(R.id.table);
Holder h = new Holder();
v.setTag(h);
// Instantiate rows
h.thumb = (ImageView) v.findViewById(R.id.img);
h.date = (TextView) createNewRow(table, "Date: ");
h.txt = (TextView) createNewRow(table, "Text: ");
return v;
}
private View createNewRow(ViewGroup group, String title) {
View row;
row = getLayoutInflater().inflate(R.layout.item_table_row, null);
((TextView) row.findViewById(R.id.title)).setText(title);
group.addView(row);
return row.findViewById(R.id.text);
}
and before someone else asks, that's the expandable_child_view layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical" >
<ImageView
android:id="#+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginLeft="40dp"
android:layout_marginRight="5dp"
android:layout_marginTop="20dp"
android:src="#drawable/ic_launcher" />
<TableLayout
android:id="#+id/table"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</TableLayout>
</LinearLayout>
as I said before, just a linear layout with a imageview and a table and a few margins.
According to Romain Guy here, this is done by design to support trackball/dpad navigation. Comment 27 has a workaround to it, by setting descendant focusability on each listview item:
setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
or
android:descendantFocusability="blocksDescendants"
I think I know what may be going on. When you do setText(), sometimes it'll wipe out a lot of stuff. You may have to use a ClickableSpan to put the link action back into the textview.
I want to display a custom view, composed of a TextView above an ImageView in a vertical LinearLayout, one at a time in a Gallery.
The problem is that my custom view does not fill the screen. I can see a part of the other views on the sides and I don't want this issue.
Here is the xml of my custom view : gallery_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gallery_item_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="#+id/gallery_item_cardname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20dp"
android:textStyle="bold"
android:text="#string/contrebandiers_lvl1"
android:textColor="#android:color/darker_gray"
/>
<ImageView
android:id="#+id/gallery_item_cardimg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:contentDescription="#string/app_name"
android:src="#drawable/contrebandiers_lvl1"
/>
</LinearLayout>
Here is the code of the method getVew of my adapter : GTRoundDeckAdapter
public View getView(int position, View convertView, ViewGroup parent)
{
GalleryItem galleryItem;
if(convertView == null)
{
galleryItem = new GalleryItem();
convertView = mInflater.inflate(R.layout.gallery_item, null);
galleryItem.cardName = (TextView) convertView.findViewById(R.id.gallery_item_cardname);
galleryItem.cardImg = (ImageView) convertView.findViewById(R.id.gallery_item_cardimg);
convertView.setTag(galleryItem);
}
else
{
galleryItem = (GalleryItem) convertView.getTag();
}
GTCard gtCard = (GTCard) mRoundDeck.get(position);
galleryItem.cardName.setText(gtCard.getNameId());
galleryItem.cardImg.setImageResource(gtCard.getImgId());
return convertView;
}
I thank you for your help.
Samuel
I would recommend that you use the ViewPager instead of Gallery. In my personal experience, I have found Gallery to slightly buggy. If your requirement is to show only one View at a time, then ViewPager (which lets you swipe left and right to go one by one) should suit your needs.
You will need to include the Android Support package to use ViewPager.
Link to support package: http://developer.android.com/sdk/compatibility-library.html
Link on how to use ViewPager: http://blog.stylingandroid.com/archives/537
you should use both the width of textview and imageview fillparent.then it will be fill the screen of the gallery...
I'm trying to display a set of data in a Grid style, using a TableLayout inside a ListView. What I want is to display each row with a different color (two colors alternatively). It works well when using a normal LinearLayout in the ListView, but for whatever reason when using a TableLayout I end up having all rows having the same background, which I think is the last one set.
For this, I am using a BaseAdapter, and in the getView function I have something like:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list, parent, false);
holder = new ViewHolder();
holder.from = (TextView) convertView.findViewById(R.id.from);
holder.to = (TextView) convertView.findViewById(R.id.to);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(position%2==0) {
convertView.setBackgroundColor(R.color.cell_background);
}
//alternate background
else {
convertView.setBackgroundColor(R.color.cell_background_alternate);
}
// Bind the data efficiently with the holder.
holder.from.setText(list.get(position)[0]);
holder.to.setText(list.get(position)[1]);
return convertView;
}
Now in my main.xml for the activity, I just have a ListView. In the list.xml used to inflate the list, I have:
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_weight="1"/>
<TextView android:id="#+id/to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_weight="1"/>
</TableRow>
</TableLayout>
Also, another problem is that the columns are not aligned: it just takes as much space as it needs for every row, every columns, when a TableLayout should align all columns. The only workaround that I came up with was to set a minimal width for the columns, but that's not pretty. Any reason why it does not work here?
Edit 21/06:
As you can see on the picture, the columns are not aligned (row 2 and 3 are but it's obviously because they have the same data inside).
try replacing
convertView = mInflater.inflate(R.layout.list, parent, false);
with
convertView = mInflater.inflate(R.layout.list, null);
and for table cell aligning issue can you give an example snapshot bcos I did not get what u trying to accomplish.
I have also faced same problem of alignment of table header and table row having data but after lot of efforts i found the only way to get rid of this problem is to give fix size to all the columns