I have a dynamic adapter that fills up a listview with textviews with values read from a JSON file, here is an example ( https://imgur.com/a/w9CHzxX ). Now I need to gather the user input from those fields and use it in a later part of my application, but my question is. when i generate textviews like that they all have the same ID right? so how can i specificly gather the user input of lets say the 2nd textview?
Adapter
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {if (convertView == null) {
holder = new ViewHolder();
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.layout_question_textfield, null, true);
---> holder.editText = (AutoCompleteTextView) convertView.findViewById(R.id.edt);
---> holder.editTitel = (Button) convertView.findViewById(R.id.btn);
convertView.setTag(holder);
}
else {...}
holder.editText.setHint(HintArrayList.get(position).getEditTextValue());
ID is an attribute of a view that scope of this attribute is limited by the inflated view group that includes this view.
for example if we have this xml file (item_view.xml):
<LinearLayout
...>
<TextView
...
android:id="#+id/textView_itemVew"/>
</LinearLayout>
and then we inflate this file several times (maybe in an adapter class) as below:
View item1 = inflater.inflate(R.layout.item_view, null,true);
View item2 = inflater.inflate(R.layout.item_view, null,true);
View item3 = inflater.inflate(R.layout.item_view, null,true);
now we can access the TextView view by it's ID but we should use the view group of this TextView to find it.
//Id's are the same but view groups no!
TextView editText_of_item1 = item1.findViewById(R.id.editText_itemVew);.
TextView editText_of_item2 = item2.findViewById(R.id.editText_itemVew);
TextView editText_of_item3 = item3.findViewById(R.id.editText_itemVew);
.
.
.
in your case you can add each EditText to a list to access it after whole list inflated ... like this:
List<EditText> editTextList = new ArrayList<>();
public View getView(int position,View view,ViewGroup parent) {
LayoutInflater inflater=context.getLayoutInflater();
View itemView = inflater.inflate(R.layout.item_view, null,true);
EditText itemEditText = (EditText) itemView.findViewById(R.id.editText);
editTextList.add(itemEditText);
return itemView;
};
there is useful example in javaTpoint website for you.
Related
The get view method from the script below crashes everytime I ran the app (the error points to that method ) this is the error :
07-11 17:25:01.147 8512-8512/com.example.android.quakereport E/AndroidRuntime:
FATAL EXCEPTION: main
Process: com.example.android.quakereport, PID: 8512
android.content.res.Resources$NotFoundException: Resource ID #0x0
and this is the ArrayAdapter from the getview method code :
public class EarthQuakeAdapter extends ArrayAdapter<Earthquake> {
public EarthQuakeAdapter(Activity context, ArrayList<Earthquake> Earthquakes) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, 0, Earthquakes);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
return super.getView(position, convertView, parent);
}
Earthquake currentEarthquake = getItem(position);
TextView magnitude = (TextView) listItemView.findViewById(R.id.magnitude);
// Get the version name from the current AndroidFlavor object and
// set this text on the name TextView
magnitude.setText(Earthquake.getmMagnitude());
// Find the TextView in the list_item.xml layout with the ID version_number
TextView place = (TextView) listItemView.findViewById(R.id.Place); // Get the version number from the current AndroidFlavor object and
// set this text on the number TextView
place.setText(Earthquake.getMplace());
// Find the ImageView in the list_item.xml layout with the ID list_item_icon
TextView date = (TextView) listItemView.findViewById(R.id.Date);
date.setText(Earthquake.getmDate());
// Get the image resource ID from the current AndroidFlavor object and
// set the image to iconView
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return listItemView;
}
I can add any code or ressource if needed just tell me on the comments.
You're never really returning the ViewHolder you inflated.
You shouldn't call super when the view is null. You should inflate it, get the child views, populate them and finally return the inflated root view.
Take a look at the docs to learn more about this process.
Try to write the adapter like this:
public class EarthQuakeAdapter extends ArrayAdapter<Earthquake> {
// ...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
Earthquake currentEarthquake = getItem(position);
TextView magnitude = (TextView) listItemView.findViewById(R.id.magnitude);
// Get the version name from the current AndroidFlavor object and
// set this text on the name TextView
magnitude.setText(Earthquake.getmMagnitude());
// Find the TextView in the list_item.xml layout with the ID version_number
TextView place = (TextView) listItemView.findViewById(R.id.Place); // Get the version number from the current AndroidFlavor object and
// set this text on the number TextView
place.setText(Earthquake.getMplace());
// Find the ImageView in the list_item.xml layout with the ID list_item_icon
TextView date = (TextView) listItemView.findViewById(R.id.Date);
date.setText(Earthquake.getmDate());
// Get the image resource ID from the current AndroidFlavor object and
// set the image to iconView
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return listItemView;
}
}
You can read more about smooth scrolling here on android's training page.
And as an option, you could switch to RecyclerView, you can read more about it here.
You shouldn't need to call super.getView(...) in the overridden getView function, and you're passing in an invalid resource ID. Simply remove that line, since you're not using its return value anyway:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItemView = convertView;
if(listItemView == null) {
listItemView = LayoutInflater.from(getContext()).inflate(
R.layout.list_item, parent, false);
}
...
}
I am trying to implement a Newsfeed-type layout with multiple feed items.
The newsfeed item would have a certain layout when collapsed, and this layout would be replaced by an 'exploded' version, when the item is clicked.
I accomplished this by using a ListView of custom items. The custom item XML layout file has a ViewStub which is what I used to change the layout back and forth.
Now, though, I wanted to 'migrate' the layout over to RecyclerView, and to also follow a ViewHolder design pattern.
The latter is what I have tried first, and I'm running into all sorts of problems.
My approach has been as follows:
Get reference to collapsed layout (events_list_item_content) and expanded layout (events_list_item_selected_content);
Get reference to a simple layout resource file to be set as the ViewStub layout (view_stub_layout).
Get ViewStub reference, set its layout (view_stub_layout) inflate, and add the collapsed layout view to this layout (when first creating the feed, all of its items are going to be collapsed).
(After initialisation, when an item is clicked) Remove previous view (layout) from the ViewStubLayout, add the other type of layout.
Here is my custom adapter class:
public class FeedRecyclerAdapter extends BaseAdapter {
public class ViewHolder {
View inflatedViewStub1;
ViewStub viewStub;
LinearLayout viewStubLayout;
LinearLayout listItemContent, listItemContentSelected;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (inflater == null)
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final FeedItem item = feedItems.get(position);
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = inflater.inflate(R.layout.events_list_item_content_new_container, parent, false);
View view = null;
view = inflater.inflate(R.layout.events_list_item_content, null);
viewHolder.listItemContent = (LinearLayout) view.findViewById(R.id.events_list_item_content);
view = inflater.inflate(R.layout.events_list_item_selected_content, null);
viewHolder.listItemContentSelected = (LinearLayout) view.findViewById(R.id.events_list_item_content_selected);
view = inflater.inflate(R.layout.view_stub_layout, null);
viewHolder.viewStubLayout = (LinearLayout) view.findViewById(R.id.view_stub_layout);
viewHolder.viewStub = (ViewStub) convertView.findViewById(R.id.list_item_feed);
(viewHolder.viewStubLayout).addView(viewHolder.listItemContent);
viewHolder.viewStub.setLayoutResource(R.layout.view_stub_layout);
viewHolder.inflatedViewStub1 = viewHolder.viewStub.inflate();
convertView.setTag(viewHolder);
} else viewHolder = (ViewHolder) convertView.getTag();
if (item.getExploded()) {
viewHolder.viewStubLayout.removeAllViews();
viewHolder.viewStubLayout.addView(viewHolder.listItemContentSelected);
} else {
viewHolder.viewStubLayout.removeAllViews();
viewHolder.viewStubLayout.addView(viewHolder.listItemContent);
}
return convertView;
}
However, when testing, the page where the Newsfeed is supposed to appear is blank.
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
stub.setLayoutResource(layoutId);
stub.inflate(); // inflate 1st layout
ll.removeAllViews(); // remove previous view, add 2nd layout
ll.addView(LayoutInflater.from(context).inflate(secondLayoutId, ll, false));
Android ViewStub change layouts programatically
When I create a class extends BaseAdapter, I get a warning message
Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling
Do I need to change my code like this suggestion? All my code is running smoothly, it's just whether it is necessary to change the code to do updata code with the latest styles? Or just need to add #SuppressLint({ "ViewHolder", "InflateParams" }) ?
My adapter
public View getView(int position, View convertView, ViewGroup parent) {
View v = inflater.inflate(R.layout.list_item, null);
TextView merchant_type = (TextView) v.findViewById(R.id.merchant_type);
TextView merchant_name = (TextView) v.findViewById(R.id.merchant_name);
TextView merchant_location = (TextView) v.findViewById(R.id.merchant_location);
VoucherBean obj = (VoucherBean) getItem(position);
merchant_type.setText(obj.getMerchantType());
merchant_name.setText(obj.getMerchantName());
merchant_location.setText(obj.getMerchantLocation());
return v;
}
If you want to change my code as recommended above warning, like what my code later? Sorry if my question is too basic for a beginner
if you have more data in your list view then you should use recycling, because it improves scrolling and performance also. here is code look like if you use view holder in your adapter.
your ViewHolder looks like
public class ViewHolder {
public TextView merchant_type;
public TextView merchant_name;
public TextView merchant_location;
}
and your getView method
View vi = convertView;
ViewHolder holder;
if (convertView == null) {
vi = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.merchant_type = (TextView) vi.findViewById(R.id.merchant_type);
holder.merchant_name = (TextView) vi.findViewById(R.id.merchant_name);
holder.merchant_location = (TextView) vi.findViewById(R.id.merchant_location);
vi.setTag(holder);
} else
holder = (ViewHolder) vi.getTag();
// now set your text view here like
holder.merchant_name.setText("Bla Bla Bla");
// return your view
return vi;
The View Holder pattern is meant to make your code easier to read and to maintain. If you look at the standard ViewHolder you'll see that its a class that basically does what you do in your getView:
private static class ExampleViewHolder{
TextView merchant_type;
TextView merchant_name;
TextView merchant_location;
public ExampleViewHolder(View view){
merchant_type = (TextView) v.findViewById(R.id.merchant_type);
merchant_name = (TextView) v.findViewById(R.id.merchant_name);
merchant_location = (TextView) v.findViewById(R.id.merchant_location);
}
}
Then in your getView method you'd get your view like this:
ExampleViewHolder holder = new ExampleViewHolder(view);
view.setTag(holder);
It's good to have them and the newer apis kind of force the use of this pattern, however as you can see by the code it doesn't change much besides readability and ease of maintenance.
However! There is an important part of the getView method that you are missing, and is most likely the reason for the warning.
The listview recycles the views, and gives them back to the adapter so that the same view doesnt have to be inflated everytime. Saves resources and a lot of memory, and you're not making use of this very important aspect of the listView.
You see, the way it recycles views is passing the old view, that you inflated before, back to the adapter through the convertView, so if the convertView is not null you can be sure its the inflated layout that you are using. So use that instead of inflating a new one:
View view = convertView;
ExampleViewHolder holder;
if(view == null){//means convertView is also null
view = inflater.inflate(yourlayout, parent, false);
holder = new ExampleViewHolder(view);
view.setTag(holder);
}else{
holder = (ExampleViewHolder) view.getTag();
}
i have a class fragmentProducts.java , which i load my products in a listview.
into my xml layout , i have texts and two spinners , one for size and one for colour. everything is ok for the texts , they are shown. I have a problem with the spinners because i think that i should add an arrayAdapter into the GetView.
i get fatal exception: E/AndroidRuntime(29244): android.content.res.Resources$NotFoundException: Resource ID #0x7f0a005b type #0x12 is not valid at android.content.res.loadXMLResourceParser(Resources.java:2407)...
my GetView code with the ViewHelper class ,is this:
`private class ViewHolder {
TextView prName;
TextView prDescription;
TextView prfprice;
ImageView prImage;
//spinners
Spinner PrVariants;
Spinner PrOptions;
int ProdPosition;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
View view = convertView;
final ProductsData info = getItem(position);
if (view == null) {
// Product row
view = mInflater.inflate(R.layout.productslistitem_layout, null);
viewHolder = new ViewHolder();
assert view != null;
viewHolder.prName = (TextView) view.findViewById(R.id.product_name);
viewHolder.prDescription = (TextView) view.findViewById(R.id.product_description);
viewHolder.prfprice = (TextView) view.findViewById(R.id.product_fprice);
viewHolder.prImage = (ImageView) view.findViewById(R.id.product_image);
**//here i try to put test values on the spinner//**
viewHolder.PrVariants = (Spinner) view.findViewById(R.id.spOptions1);
String[] names = {"test1","test2","test3"};
var1Adapter = new ArrayAdapter<String>(getActivity(),R.id.spOptions1,names);
var1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
viewHolder.PrVariants.setAdapter(var1Adapter);
viewHolder.prfprice.setText("120.00" + "€");
viewHolder.prName.setText(info.getPrName());
viewHolder.prDescription.setText(info.getPrComments());
view.setTag(viewHolder);
} else
viewHolder = (ViewHolder) view.getTag();
return view;
}`
Does anyone understand the error message? should i not use arrayadapter into the GetView function?
Resources$NotFoundException: Resource ID #0x7f0a005b type #0x12
Because ArrayAdapter take Layout id instead of View id as second parameter.
var1Adapter = new ArrayAdapter<String>(getActivity(),
<Layout_Id_In_Which_Spinner_Added>,names);
thank you,unfortunatelly i could not make it work with your answer:
var1Adapter = new ArrayAdapter<String>(getActivity(),R.id.layoutspOptions1,names).
//layoutspOptions1 is the linearLayout id that i have the spinner in.
Although it worked by changing the arrayAdapter to:
`var1Adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_spinner_item,names);
var1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);`
So, we dont use the R.id.spinnerId as a second parameter of the ArrayAdapter but a default layout : android.R.layout.simple_spinner_item
I have a listview that uses a customadapter based on the baseadapter. The listview populates ok using external data and I can pick up the click events and know which item has been selected.
I'm having a problem updating the clicked item's views, like TextView and ViewFlipper.
Do I have to update something via the listview or is it via the adapter. I've tried things like the following;
View test = (View)adapter.getView(pos, null, myListView);
ViewFlipper temp = (ViewFlipper)test.findViewById(R.id.flipholder);
temp.showNext();
TextView temp2 = (TextView)test.findViewById(R.id.filmtitle);
temp2.setText("Hello World");
Which results in the viewfliper flipping the first and third item or second and fourth and the text not updating at all.
Any ideas?
Cheers
Try this pattern in getView:
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
ViewHolder holder;
// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
return convertView;
}
static class ViewHolder {
TextView text;
ImageView icon;
}
}