0

In my activity I am adding a header button to save the values of a listview, with an EditText and post them to a php/mysql web app.

I am able to get the values of the listview if I use setOnItemClickListener but when I use setOnClickListener on the header save button, I am not able to iterate through the listview.

I am using a custom array adaptor :-

public class CustomOrderAdaptor extends ArrayAdapter{ int groupid;

ArrayList<OneOrder> records;

Context context;



public CustomOrderAdaptor(Context context, int vg, int id, ArrayList<OneOrder>records) {

    super(context, vg, id, records);

    this.context = context;

    groupid = vg;

    this.records = records;



}



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



    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View itemView = inflater.inflate(groupid, parent, false);

    TextView textName = (TextView) itemView.findViewById(R.id.product_name);
    textName.setText(records.get(position).getproduct_name());

    EditText new_quantity = (EditText) itemView.findViewById(R.id.new_quantity);
    new_quantity.setText(records.get(position).getnew_quantity());

    TextView textOrderitemid = (TextView) itemView.findViewById(R.id.order_item_id);
    textOrderitemid.setText(records.get(position).getorder_item_id());

    TextView textQuantity = (TextView) itemView.findViewById(R.id.quantity);
    textQuantity.setText(records.get(position).getquantity());



    return itemView;

}

}

data model :-

public class OneOrder {
private String quantity;
private String new_quantity;
private String product_name;
private String order_item_id;



public void setquantity(String quantity){this.quantity=quantity;}
public void setnew_quantity(String new_quantity){this.new_quantity=new_quantity;}
public void setproduct_name(String product_name){this.product_name=product_name;}
public void setorder_item_id(String order_item_id){this.order_item_id=order_item_id;}



public String getquantity(){return quantity;}
public String getnew_quantity(){return new_quantity;}
public String getproduct_name(){return product_name;}
public String getorder_item_id(){return order_item_id;}

}

My activity is :-

protected void onCreate(Bundle savedInstanceState) {

    //TODO Auto-generated method stub

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_get_order);

    context = this;

    records = new ArrayList<OneOrder>();

    listOrder = (ListView) findViewById(R.id.order_item_list);

    LayoutInflater inflater = LayoutInflater.from(this);
    View nTop = inflater.inflate(R.layout.activity_get_order_footer, null);
    listOrder.addHeaderView(nTop);


    adapter = new CustomOrderAdaptor(context, R.layout.list_order, R.id.product_name,
            records);


    listOrder.setAdapter(adapter);

    Button mButton = (Button) nTop.findViewById(R.id.button_save);

    mButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            JSONObject order_items = new JSONObject();
            JSONObject sendObject = new JSONObject();
            for (int i=0;i<adapter.getCount();i++){
                JSONObject order_item = new JSONObject();
                OneOrder current_order = (OneOrder) listOrder.getAdapter().getItem(i);
                //OneOrder current_order = (OneOrder) getListView().getItemAtPosition(i);
                try {
                    order_item.put("quantity", current_order.getquantity().toString());
                    order_item.put("new_quantity", current_order.getnew_quantity().toString());
                    order_item.put("order_item_id", current_order.getorder_item_id().toString());
                    order_items.put(String.valueOf(i),order_item);

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
            HttpURLConnection conn = null;
            try {
                Intent i = getIntent(); // gets the previously created intent
                String order_id = i.getStringExtra("order_id");
                sendObject.put("items", order_items.toString());
                sendObject.put("order_id", order_id);
                try {
                    URL url = new URL("http://192.168.0.70/steam_dos/index.php?option=com_steam&section=linen&task=save_order_out");
                    String message = sendObject.toString();

                    conn = (HttpURLConnection) url.openConnection();
                    conn.setReadTimeout( 10000 /*milliseconds*/ );
                    conn.setConnectTimeout( 15000 /* milliseconds */ );
                    conn.setRequestMethod("POST");
                    conn.setDoInput(true);
                    conn.setDoOutput(true);
                    conn.setFixedLengthStreamingMode(message.getBytes().length);

                    //make some HTTP header nicety
                    conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
                    conn.setRequestProperty("X-Requested-With", "XMLHttpRequest");

                    //open
                    conn.connect();

                    //setup send
                    BufferedOutputStream os = new BufferedOutputStream(conn.getOutputStream());
                    os.write(message.getBytes());
                    //clean up
                    os.flush();

                    //do something with response
                    InputStream is = conn.getInputStream();
                }catch (MalformedURLException e) {
                    e.printStackTrace();

                } catch (IOException e) {

                    e.printStackTrace();

                }


            } catch (JSONException e) {
                e.printStackTrace();
            }


        }
    });






}

the error is here :-

 order_item.put("quantity", current_order.getquantity().toString());

the error is simple :-

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String au.com.southportsteamlaundry.rfid.steamscanadditions.OneOrder.getquantity()' on a null object reference

The view looks like this :-

Layout view

I am trying to save all of the values of the listview after the save button is clicked but I am not getting the listview items with that code, could you please explain the best way to achieve that ? Thanks.

user1911778
  • 11
  • 1
  • 2
  • Just keep a local reference to the ArrayList that you pass into the custom adapters constructor inside of the owning activity. Inside of your OnItemClickListener store the selected indices inside of a boolean [] that is initialized to the same size as the ArrayList. Once the header button is selected just iterate over the boolean array and the indexes with a true value grab that corresponding index inside of the ArrayList and store them inside of a temporary list and upload that to your database. – cincy_anddeveloper Feb 14 '17 at 01:06
  • Thanks Wade - If I understand you correctly, when I get the json object from the php/mysql web app, I should save the data in a local array and pull the values after the save button is clicked ? How do I get the values of the EditTexts that sit in the listview, one EditText per row. – user1911778 Feb 14 '17 at 23:05
  • clearly a case of over think by a java nube. I was getting a json object from php, i only needed to declare that JsonArray at the top of the activity and was then able to access it and post it back for processing. I moved the HttpURLConnection into an async task as it was crashing. I still need to work out how to access the EditTexts next to each listview row. – user1911778 Feb 15 '17 at 05:12
  • You are getting a crash from HttpURLConnection because as of android API 11 (Honeycomb) the API will through a NetworkOnMainThreadException when you make a network call on the Main thread. – cincy_anddeveloper Feb 15 '17 at 15:39
  • As for getting the EditText values for each ListView row that'll be tricky and will require a little bit of a workaround because the rows will either get garbage collected or recycled, depending on how you implemented it. What you'll want to do is create an additional field in the data model that represents the list row, that'll hold the text inside of the EditText and gets updated whenever the text changes. – cincy_anddeveloper Feb 15 '17 at 15:40

2 Answers2

0

Normally it's not recommended to use Edit text with adapter, the reason is edit text saving cannot be handled when it scroll out.

There are two kinds solution.

  1. Replace the listview with scrollview

2 create a variable and add a TextWatcher on the edittext. Whenever the edittext get modified, the text watcher detect the change and override the variable whener you done something on it.

code would be like Implementing Text Watcher for EditText

Community
  • 1
  • 1
TaoBit
  • 852
  • 7
  • 10
  • Thanks TaoBIt, I will look at scroll view, although I doubt there will ever be scrolling in this context. There shouldn't be too many order items per order and the private app will run on a tablet. I still don't know from your answer how I should get all of the values of the listview / scrollview though or how to get the matching EditText for that row. – user1911778 Feb 14 '17 at 23:09
  • I wouldn't recommend this because you'd have to load all of the views for the order items on screen at once. If you have a large list of order items, you'd wouldn't want to load all of the views them as this will eat up a lot of memory and will have a performance overhead during initial load. ListView, unlike ScrollView, only draws the views that can be displayed on the screen at once and internally has fairly complex logic to handle recycling views to be used again either at the top and bottom of the list depending on the scroll direction which greatly saves on memory. – cincy_anddeveloper Feb 15 '17 at 15:49
  • Yes, @Wade Wilson. Using scroll view would be better when you know that the data is not that much. Overall, EditText is not very compatible wth listview/recyclerview because when the row scroll out of the screen the data get clean. If you still have to use it, I would recommend use Text Watcher in EditText. And also you need to be carefull to handle the keyboard focus on EditText in the listview/scrollview – TaoBit Feb 15 '17 at 18:38
  • @TaoBit I agree, I believe the best solution is to remove the EditText field from the ListView and replace it with a TextView and an edit button that will launch a Dialog with an EditText view in it and perform the desired action from there. – cincy_anddeveloper Feb 15 '17 at 18:47
0

my answer may not be the best one, but this is what I implemented to get the EditText values of the list view :

mButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            JSONObject order_item = new JSONObject();
            order_items_edited = new JSONObject();
            for (int i = 0; i < listOrder.getCount(); i++) {
                EditText et = (EditText) listOrder.getChildAt(i).findViewById(R.id.new_quantity);
                if (et!=null) {

                    TextView oi = (TextView) listOrder.getChildAt(i).findViewById(R.id.order_item_id);
                    Log.i("dtag", "et is " + String.valueOf(et.getText()));
                    Log.i("dtag", "oi is " + String.valueOf(oi.getText()));
                    try {
                        order_item.put("new_quantity", String.valueOf(et.getText()));
                        order_item.put("order_item_id", String.valueOf(oi.getText()));
                        order_items_edited.put(String.valueOf(i),order_item);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }

the main issue I was having was a null object for et, which is valid, but I wasn't testing for it.

Now its working, I will look at implementing a cleaner solution.

user1911778
  • 11
  • 1
  • 2