Reputation: 4124
In my application I have to generate a big form with lot of elements (an element is usually and label + attribute (edditext, spinner, checkbox,...)).
When a form contains more elements (>20), the application is start lagging, opening the keyboard by example take around 1-2sec or the scrolling is slow.
What I tried
At the moment each element is inflated from xml (a LinearLayout with a TextView and another component) and added to form layout. I tried to "re-use" (practically re-add) an element but I got and exception saying that the View already has a parent which make sense since I was already added to my form layout.
I tried to add all the elements in a ListView to make sure that the views are re-used. It is working but not verry good: the problem in this case is that if I have an EditText, the user enter some text and scroll to bottom of the list, I couldn't find a way to save the text from EditText so I will be added back in EditText when the element will be visible again in ListView (the user scroll back to my element).
Question
Do you know any way to use lot of UI components but in same time to keep a good app performance? Do you think it is possible to get the text from an EditText just before the user start the scroll?
Thank you.
Upvotes: 1
Views: 1978
Reputation: 36289
Sounds like you have some sort of preference screen. If that is the case, consider using PreferenceActivity. If that will not work, what about a ListView
, which has built-in methods for reusing layout? If neither of these options will work, you can create your own ViewAdapter, which works in very much the same way as a ListView
. Simply create a class - such as MyViewAdapter
. It should take in arguments to help configure what it will look like - such as the label text and what the other element is:
public class MyViewAdapter {
public static enum InputType {
editor, spinner, checkbox
};
private CharSequence labelText;
private InputType input;
public MyViewAdapter(CharSequence text, InputType inputType) {
this.labelText = text;
this.input = inputType;
}
}
As for knowing what text is inside your EditText
- just use TextWatcher to listen for changes to the text. Although you can get before and after scroll callbacks, it requires hacking the built-in ScrollView
. This example is added into the below code.
Next, add a method called getView(Context)
as follows:
public View getView(Context context) {
//here is where you inflate your view. For example:
LinearLayout ll = new LinearLayout(context);
ll.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
ll.setOrientation(LinearLayout.VERTICAL);
TextView tv = new TextView(context);
tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tv.setText(labelText);
ll.addView(tv);
switch (input) {
case (InputType.spinner) : {
//TODO (see editor example)
break;
}
case (InputType.checkbox) : {
//TODO (see editor example)
break;
}
default ://default to editor
case (InputType.editor) : {
EditText et = new EditText(context);
et.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
et.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after){
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
ll.addView(et);
break;
}
}
return ll;
}
Finally, to use this ViewAdapter, create them in your main activity:
List<MyViewAdapter> adapters = new ArrayList<MyViewAdapter>();//easy way to manage these.
//for each adapter, do something like:
adapters.add(new MyViewAdapter("myText:", InputType.editor));
Then, to inflate the views, do:
//Let's say your Main View is a LinearLayout called myView.
for (MyViewAdapter adapter : adapters) {
myView.addView(adapter.getView(context));
}
Upvotes: 3