There are some similar questions to this but I can't find one that goes as far as I want. I am using a custom class stored in an ArrayAdapter to populate a ListView with linear layouts that I can customise by modifying the class - which is working in that I have a button in each which does exactly what I want. The LinearLayout looks like: [TextView][EditText][Button] and when the Button is clicked, it does some DB stuff with the contents of the EditText. That's all fine.
The problem I have is that I want to (for example) update the text contents of an EditText in 1 layout within the ListView, in my activity rather than in the class where the view is created and the Button listener set and so on. I may also want to say "disable the Button in the second item of the list view" etc..
I've tried a lot of different approaches, passing around contexts or calling methods on the adapter vs on the actual list of objects, making the EditText a member variable with a getter, and I always get either nothing happening or I reach a NullPointerException when looking for the EditText by ID.
Is this even possible? Do I need to create a final variable to hold each EditText and somehow pass this back to the activity or something? I will end up with multiple views within my activity that have the same id, but they'll have been created by separate objects
Ultimately what I'm trying to do is make it so I can abstract my GUIs a bit. Currently I have 8 activities which are about 90% identical, but I have duplicated code setting up the views in each activity. I want to instead abstract this out into classes where I can say "give me a new text input line with whatever label and I will override the button behaviour" and then refactor down to 1 activity for this task. When a user inputs data in one of the 'rows' then the activity may need to update one of the other rows, (or clear 1 when the back button is pressed etc) which is why I want to be able to call back to a specific view within the layout within the object within the array adapter :D
for example I want to be able to create 3 new textInputLineBuilder objects (probably subclass this eventually) and have them displayed like:
[Name:][NameEditText][Button]
[Stock:][StockEditText][Button]
[Quantity:][QuantityEditText][Button]
here's the (cut down) layout, activity_row.xml
which the custom object inflates and returns to the ArrayAdapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout>
<TextView
android:id="@+id/rowLabel"/>
<EditText
android:id="@+id/rowInput"/>
<Button
android:id="@+id/rowButton"/>
</LinearLayout>
here is the relevant code in the activity:
public class AnActivity implements UICallBack {
private ListView listOfInputs;
private ArrayList<UIElementInterface> listOfUIElements;
private UIElementsAdapter UIAdapter;
protected void onCreate() {
listOfInputs = (ListView) findViewById(R.id.listInputs);
listOfUIElements = new ArrayList<>();
listOfUIElements.add(new textInputLineBuilder("<label>", this)); //this implements a callback interface
//add a few more
UIAdapter = new UIElementsAdapter(this.getApplicationContext(), listOfUIElements);
UIAdapter.notifyDataSetChanged();
listOfInputs.setAdapter(UIAdapter);
}
public void updateUIState() {
//I have tried all sorts here
for (int i=0; i<listOfUIElements.size(); i++) {
UIAdapter.setTheText("test "+i, i);
}
UIAdapter.notifyDataSetChanged;
listOfInputs.setAdapter(UIAdapter);
}
}
I then have my ArrayAdapter class, UIElementsAdapter.java
which retrieves the appropriate object from the list and then calls getRowView
in order to get the object to inflate the layout that will make up this 'row'
public class UIElementsAdapter extends ArrayAdapter<UIElementInterface> {
private final Context context;
public UIElementsAdapter(Context context, ArrayList<UIElementInterface> listOfUIElements) {
super(context, 0, listOfUIElements);
this.context = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return getItem(position).getRowView(context, parent); //retrieves the UIElementInterface object aka textInputLineBuilder object
}
public void setTheText(String s, Integer position) {
try {
getItem(position).setEditText(s);
} catch(NullPointerException e) {
e.printStackTrace();
}
}
}
and finally I have textInputLineBuilder.java
which implements the UIElementInterface (getRowView & setEditText)
public class textInputLineBuilder implements UIElementInterface {
private View convertView;
public textInputLineBuilder(String label, UICallBack callback) {
this.labelText = label;
this.callback = callback; //used with button onclicklistener
}
public View getRowView(Context context, ViewGroup parent) {
LayoutInflater layout = LayoutInflater.from(context);
convertView = layout.inflate(R.layout.activity_row, parent, false);
label = (TextView) convertView.findViewById(R.id.rowLabel);
fuzzy = (Button) convertView.findViewById(R.id.rowButton);
input = (EditText) convertView.findViewById(R.id.rowInput);
final EditText inputFinal = input; //for the button listener. was trying using input as a member variable for setEditText but that didn't work
label.setText(labelText);
//add onclicklistener for the fuzzy button. works fine
return convertView;
}
public void setEditText(String s) {
//I have tried all sorts here, passing in context from various places, passing in layout inflaters etc
EditText e = (EditText) convertView.findViewById(R.id.rowInput);
e.setText(s);
}
}