5

I've got a ListView with a customer ArrayAdapter and a custom ListItem-XML. At the bottom of this ListView I've added a FooterView with a Button. Now I want to get all the values of the three EditTexts in each of my ListItems when I click this Button.

Here below is my code:

activity_checklistresult.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

result_inner_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center">

    <TextView
        android:id="@+id/tv_result_amount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/default_margin" />
    <EditText
        android:id="@+id/et_result_amount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/default_margin"
        android:inputType="number" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_result_product_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:ellipsize="end"
            android:layout_margin="@dimen/default_margin" />
        <AutoCompleteTextView
            android:id="@+id/actv_search_product"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:singleLine="true"
            android:ellipsize="end"
            android:layout_margin="@dimen/default_margin"
            android:inputType="textAutoComplete" />

    </LinearLayout>

    <TextView
        android:id="@+id/tv_result_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/default_margin" />
    <EditText
        android:id="@+id/et_result_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/default_margin"
        android:inputType="numberDecimal" />

</LinearLayout>

ResultListActivity.java:

public class ChecklistResultActivity extends ListActivity
{
    private MyResultAdapter adapt;
    private Button confirmButton;
    private ChecklistResultActivity rActivity;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_checklistresult);

        // Set my Custom ArrayAdapter for this ListActivity
        setAdapter();

        rActivity = this;
    }

    private void setAdapter(){
        adapt = new MyResultAdapter(this, R.layout.result_inner_view, Controller.getInstance().getOrderedProducts());
        setListAdapter(adapt);

        // Add the confirm button at the end of the list
        addFooterConfirmButton();
    }

    private void addFooterConfirmButton(){
        ListView lv = (ListView)findViewById(android.R.id.list);
        FrameLayout footerLayout = (FrameLayout) getLayoutInflater().inflate(R.layout.result_footer_view, null);
        confirmButton = (Button)footerLayout.findViewById(R.id.confirm_result_button);
        confirmButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ...

                // Get all EditText values (and compare them with the Default Value)
            }
        });
        lv.addFooterView(footerLayout);
    }

    ...

MyResultAdapter.java:

public class MyResultAdapter extends ArrayAdapter<OrderedProduct>
{
    private Context context;
    private int layoutResourceId;
    private LayoutInflater inflater;

    public MyResultAdapter(Context c, int layoutResourceId, List<OrderedProduct> objects){
        super(c, layoutResourceId, objects);
        this.layoutResourceId = layoutResourceId;
        this.context = c;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        View view = convertView;
        if(view == null)
            view = inflater.inflate(layoutResourceId, parent, false);

        ...

        return view;
    }
}

In the ResultListActivity at // Get all EditText values (and compare them with the Default Value) I want to loop through all the OrderedProducts and compare the default values of those, with the new filled-in values of the two EditTexts and the AutoCompleteTextView. So how can I get those values from within the onClick of the Footer-Button?

Thanks in advance for the responses.

2
  • What is happening now? Are you getting only the last value? Commented May 30, 2014 at 11:16
  • use edit text change listener on edit text as you will enter value into edit text at that time save value into object according to position after that you can get all values from that object. Commented May 30, 2014 at 11:17

2 Answers 2

14

Your adapter has to save text on change for each created EditText :

  1. create a map to save values
  2. Define and set a generic TextWatcher for every EditText
  3. set a Tag on the editText (using its position or any id you want) we'll use this tag as the key in the hashMap
  4. create a method to retrieve the value for a given EditText

Adapter :

public class MyResultAdapter extends ArrayAdapter<OrderedProduct>
{
    ...

    private HashMap<String, String> textValues = new HashMap<String, String>();

    ...

    public ViewView getView(int position, View convertView, ViewGroup parent){

        View view = convertView;
        boolean convertViewWasNull = false;
        if(view == null){
            view = inflater.inflate(layoutResourceId, parent, false);
            convertViewWasNull = true;
        }


        myEditText1 = findViewById...
        myEditText2 = findViewById...

        if(convertViewWasNull ){

            //be aware that you shouldn't do this for each call on getView, just once by listItem when convertView is null
            myEditText1.addTextChangedListener(new GenericTextWatcher(myEditText1));
            myEditText2.addTextChangedListener(new GenericTextWatcher(myEditText2));
        }

        //whereas, this should be called on each getView call, to update view tags.
        myEditText1.setTag("theFirstEditTextAtPos:"+position);
        myEditText2.setTag("theSecondEditTextAtPos:"+position);
    }


    private class GenericTextWatcher implements TextWatcher{

       private View view;
       private GenericTextWatcher(View view) {
            this.view = view;
        }

        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

        public void afterTextChanged(Editable editable) {

            String text = editable.toString();
            //save the value for the given tag :
            MyResultAdapter.this.textValues.put(view.getTag(), editable.toString());
        }
    }

    //you can implement a method like this one for each EditText with the list position as parameter :
    public String getValueFromFirstEditText(int position){
          //here you need to recreate the id for the first editText
         String result = textValues.get("theFirstEditTextAtPos:"+position);
         if(result ==null)
              result = "default value";

         return result;
    }

    public String getValueFromSecondEditText(int position){
          //here you need to recreate the id for the second editText
         String result = textValues.get("theSecondEditTextAtPos:"+position);
         if(result ==null)
              result = "default value";

         return result;
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Though I changed some small things to make it more dynamic (like only one getValueOfEditText method with a String as parameter and such), this does indeed solve my problem. Thanks and accepted as answer.
Quote: "//be aware that you shouldn't do this for each call on getView, just once by listItem when convertView is null" I just found out that this isn't true, you should also call this when you are scrolling up or down in the ListView, since this resets the saved values of the EditTexts to their default values.
4

You can store all edittext values and get them when needed, you can store it in afterTextChange or onTextChange, it's up to you.

public class MyResultAdapter extends ArrayAdapter<OrderedProduct>{
    ...

    private final String[] valueList;

    public MyResultAdapter(Context c, int layoutResourceId, List<OrderedProduct> objects){
        super(c, layoutResourceId, objects);

        ...

        valueList = new String[objects.size()];

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        View view = convertView;
        if(view == null)
            view = inflater.inflate(layoutResourceId, parent, false);

        ...

        //for edittext add text watcher listener

        final pos = position;

        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                 valueList[pos] = s.toString();
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });

        return view;
    }

    public String[] getValueList(){
        return valueList;
    }
}

4 Comments

How do you manage several EditText on the same line ? in your case you've got just one. Moreover be carefull you a calling 'new TextWatcher()' on each 'getView' call, that can be very heavy and is really bad for list performances.
this is an example to user to understand the approach, it's not the fully answer of course, rest is up to him to adjust his own implementation and I disagree with the performance point. Listview already is recycle and handle performances issues. And what performance issue do you think it can cause?
You are creating to many new TextWatcher even when its not needed since you've got a convertView with an already set TextWatcher to reuse.
I see your point now, but as I said I'm just giving an approach and it's about how you can have a listener to watch. I didn't implement all code etc and no intention to do that. this initialize is when your convertview is null. You can have holder pattern to keep reference etc etc. But this all up to user to implement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.