0

I have pulled xml from a RESTful service and am placing it a XMLPullParser. I then am trying to populate a listview with the information. I am new to XML parsing and not sure why it's not populating the list with data from the response.

My code is as followed:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        context = getApplicationContext();

        listView = (ListView) findViewById(R.id.contactListView);

        OkHttpClient client = getUnsafeOkHttpClient();
        Request request = new Request.Builder()
                .url(myURL)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseData = response.body().string();
                InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                List<PeepWithPic> peepWithPics;
                XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                peepWithPics = parserHandler.parse(stream);
                ArrayAdapter<PeepWithPic> adapter = new ArrayAdapter<>(getApplicationContext(),
                        R.layout.contact_cardview_layout, peepWithPics);
                listView.setAdapter(adapter);


            }
        });

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

public class XMLPullParserHandler {
    List<PeepWithPic> peepWithPicList;
    private PeepWithPic peepWithPic;
    private String text;

    public XMLPullParserHandler() {
        peepWithPicList = new ArrayList<>();
    }

    public List<PeepWithPic> getPeepWithPicList() {
        return peepWithPicList;
    }

    public List<PeepWithPic> parse(InputStream is) {
        XmlPullParserFactory factory = null;
        XmlPullParser parser = null;
        try {
            factory = XmlPullParserFactory.newInstance();
            factory.setNamespaceAware(true);
            parser = factory.newPullParser();

            parser.setInput(is, null);

            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                String tagname = parser.getName();
                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if (tagname.equalsIgnoreCase("PeepWithPic")) {
                            // create a new instance of employee
                            peepWithPic = new PeepWithPic();
                        }
                        break;

                    case XmlPullParser.TEXT:
                        text = parser.getText();
                        break;

                    case XmlPullParser.END_TAG:
                        if (tagname.equalsIgnoreCase("PeepWithPic")) {
                            // add employee object to list
                            peepWithPicList.add(peepWithPic);
                        } else if (tagname.equalsIgnoreCase("First_name")) {
                            peepWithPic.setFirst_name(text);
                        } else if (tagname.equalsIgnoreCase("Last_name")) {
                            peepWithPic.setLast_name(text);
                        } else if (tagname.equalsIgnoreCase("Payroll_title")) {
                            peepWithPic.setPayroll_title(text);
                        /*} else if (tagname.equalsIgnoreCase("email")) {
                            peepWithPic.setEmail(text);*/
                        } /*else if (tagname.equalsIgnoreCase("type")) {
                            peepWithPic.set(text);
                        }*/
                        break;

                    default:
                        break;
                }
                eventType = parser.next();
            }

        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return peepWithPicList;
    }
}
Adam Gardner
  • 1,216
  • 1
  • 9
  • 21
  • Possible duplicate of [CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch views](http://stackoverflow.com/questions/3280141/calledfromwrongthreadexception-only-the-original-thread-that-created-a-view-hie) – Isaac Jan 05 '17 at 23:10

1 Answers1

1

That error occurs when you attempting to modify the view outside of the UI thread. Without having the stacktrace for which line is causing the problem I can't give an exact answer as to what will fix the problem. However here is where the problem starts: you are manipulating your UI from within the onResponse call. You can try updating your code to look like this:

client.newCall(request).enqueue(new Callback() {
            Handler mainHandler = new Handler(context.getMainLooper());
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseData = response.body().string();
                InputStream stream = new ByteArrayInputStream(responseData.getBytes());

                mainHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        List<PeepWithPic> peepWithPics;
                        XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                        peepWithPics = parserHandler.parse(stream);
                        ArrayAdapter<PeepWithPic> adapter = new ArrayAdapter<>(getApplicationContext(),
                                R.layout.contact_cardview_layout, peepWithPics);
                        listView.setAdapter(adapter);
                    }
                });


            }
        });

However since you also have the XmlPullParser within this you may get an ANR if it takes too long to parse this. So ideally you'd want to move your listView calls outside of the onResponse and then from within your XmlPullParser you can do something similar with the Handler mainHandler = new Handler(context.getMainLooper()); to pass UI updates back to the main thread.

CodyEngel
  • 1,501
  • 14
  • 22
  • With adding the Handler, I am not sure what the 3 methods it wants me to add to allow that are for. But the line I am getting the CalledFromWrongThreadExctiopn is on the listView.setAdapter(adapter) – Adam Gardner Jan 06 '17 at 14:01
  • The quick answer is that the handler will allow you to pass stuff off to another thread, in this case the Main thread which is the only one that should touch UI components. – CodyEngel Jan 06 '17 at 14:50
  • So I pass the listview inside the publish method? Sorry still new to Android and never used a handler before. – Adam Gardner Jan 06 '17 at 14:55
  • Have you tried replacing the `client.newCall(...)` with the code I've posted in my answer? That should be all you need to do to resolve the issue for this question. You may however get a new error for doing too much on the main thread since you are parsing XML. – CodyEngel Jan 06 '17 at 15:23
  • Thank you, it does work. I haven't run into ANR as there isn't much coming back from the URL. Now to learn to parse XML because it's one giant text string. – Adam Gardner Jan 06 '17 at 15:53
  • Glad to hear that Adam. It's best practice to parse XML on a background thread, but if it's small enough you won't run into an ANR. However I'd recommend trying to restructure your code so that the XML parsing is done on a background thread. Feel free to reach out again with questions regarding that and I can try to point you to some good resources. – CodyEngel Jan 06 '17 at 16:03