2

I'm trying to parse XML from URL and not getting any data, when I debug I see that I'm stuck in the while() loop. The variable i came up to 160 before I gave up. I don't get why I'm stuck in the while loop and not getting into any of the if statements in the loop.

public class Task extends AsyncTask<Void,Void,Void> {
private List<Task> tasks;

public Task()
{

}

@Override
protected Void doInBackground(Void... params) {
    makeTask();
    return null;
}

public Task(String title){
    mTitle = title;
}

private List<Task> makeTask(){
    int i = 0;
    tasks = new ArrayList<>();

    try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        URL url = new URL("http://xxx");
        InputStream stream = url.openStream();
        xpp.setInput(stream, null);
        int eventType = xpp.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_DOCUMENT) {
            }
            else if (eventType == XmlPullParser.END_DOCUMENT) {
            }
            else if (eventType == XmlPullParser.START_TAG) {
                if (xpp.getName().equalsIgnoreCase("Task")) {
                    tasks.add(new Task(xpp.nextText()));
                    Log.d("Task: ", xpp.nextText());
                }
                else if (eventType == XmlPullParser.END_TAG) {
                }
                else if (eventType == XmlPullParser.TEXT) {
                }
                eventType = xpp.next();
            }
            i++;
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (XmlPullParserException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return tasks;
}

Edit:

This is the new while() loop and working thanks to @imsiso

while (eventType != XmlPullParser.END_DOCUMENT) {
           if (eventType == XmlPullParser.START_TAG) {
                if (xpp.getName().equalsIgnoreCase("name")) {
                    tasks.add(new Task(xpp.nextText()));
                }
                eventType = xpp.next();
            }
            else
               eventType = xpp.next();

The line below in the code List<Task> tasks = task.getTasks(); is giving error:

java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference

I'm think that I'm getting that error because I'm not waiting for the AsyncTask to finish and don't know how I should do that.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup   container,         Bundle savedInstanceState) {

    /*Removed irrelevant code here*/

     Task task = new Task();
     new Task().execute();


     List<Task> tasks = task.getTasks();

     mAdapter = new TaskAdapter(tasks);
     mTaskRV.setAdapter(mAdapter);
     return view;
}
Aleksandar G
  • 1,163
  • 2
  • 20
  • 25
neX
  • 35
  • 8
  • You are parsing a JSON or XML? Code doesn't match your question title. – Rohit5k2 Feb 27 '16 at 18:54
  • Yea, I'm parsing XML, I don't know why I wrote JSON. Thanks, edited now. – neX Feb 27 '16 at 18:55
  • Just from your code it seems it get stuck in first step. Cause for the case condition start_document gets triggered u don't change anything like Xpp.next so the same thing happens again and again – Sina R. Feb 27 '16 at 19:06
  • @imsiso I removed all the if statements but kept if (eventType == XmlPullParser.START_TAG), why doesn't it ever get true and why am I still stuck in the loop? – neX Feb 27 '16 at 19:12
  • Let me tell u I am only using logic and don't know the code you are using. So try this. If(.start_tag){blabla}else{xpp.next();} so if your condition don't get true then xpp.next should move you to next node or something then no loop will happen. If that work it will help you get one step closer – Sina R. Feb 27 '16 at 19:17
  • @imsiso I tried to set eventype = xpp.next() in else statement after the only if statement I have now, but now I get this exception: " org.xmlpull.v1.XmlPullParserException: precondition: START_TAG (position:END_TAG @5:32 in java.io.InputStreamReader@52734bb" – neX Feb 27 '16 at 19:25
  • @imsiso Seems like it indeed was a one step closer because now at least i'm getting the data in to my arraylist even it's not showing on screen(but that's whole other issue), thank you so much! – neX Feb 27 '16 at 19:30
  • Yw. I'm reading about it and have found some possible reasons. Show me latest code you are using. And let's solve it together – Sina R. Feb 27 '16 at 19:42
  • @imsiso Thanks, check the edit please. – neX Feb 27 '16 at 19:50

3 Answers3

1

Here's an example TaskLoader and Callback for Loader.

private LoaderManager.LoaderCallbacks<List<TaskModel>> mLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<TaskModel>>()
{
    @Override
    public Loader<List<TaskModel>> onCreateLoader(int id, Bundle args)
    {
        return new TaskLoader(getContext());
    }

    @Override
    public void onLoadFinished(Loader<List<TaskModel>> loader, List<TaskModel> data)
    {
        mTaskRV.setAdapter(new TaskAdapter(data));
    }

    @Override
    public void onLoaderReset(Loader<List<TaskModel>> loader)
    {
        //
    }
};

And the TaskLoader.

private static class TaskLoader extends AsyncTaskLoader<List<TaskModel>>
{
    private static final String TAG = TaskLoader.class.getSimpleName();

    private List<TaskModel> mData = null;


    public TaskLoader(Context context)
    {
        super(context);
    }

    @Override
    protected void onStartLoading()
    {
        super.onStartLoading();
        if(mData != null){
            deliverResult(mData);
        }
        if(takeContentChanged() || mData == null){
            forceLoad();
        }
    }

    @Override
    public void deliverResult(List<TaskModel> data)
    {
        mData = data;
        super.deliverResult(data);
    }

    @Override
    public List<TaskModel> loadInBackground()
    {
        try{
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            factory.setNamespaceAware(true);
            XmlPullParser xpp = factory.newPullParser();
            URL url = new URL("http://xxx");
            InputStream in = null;
            try{
                in = url.openStream();
                xpp.setInput(in, "UTF-8");
                return parseTasks(xpp);
            }
            finally{
                if(in != null){
                    in.close();
                }
            }
        }
        catch(MalformedURLException e){
            Log.e(TAG, "loadInBackground", e);
        }
        catch(XmlPullParserException e){
            Log.e(TAG, "loadInBackground", e);
        }
        catch(IOException e){
            Log.e(TAG, "loadInBackground", e);
        }
        return null;
    }

    private List<TaskModel> parseTasks(XmlPullParser xpp)
        throws XmlPullParserException, IOException
    {
        ArrayList<TaskModel> tasks = new ArrayList<>();
        int eventType = xpp.getEventType();
        while(eventType != XmlPullParser.END_DOCUMENT){
            if(eventType == XmlPullParser.START_TAG){
                if(xpp.getName().equalsIgnoreCase("description")){
                    tasks.add(new TaskModel(xpp.nextText()));
                }
            }
            eventType = xpp.next();
        }
        return tasks;
    }
}
Simon
  • 10,932
  • 50
  • 49
0

You should provide a listener to the async task that will be triggered when the doInBackground() completes. For instance:

public interface TaskListener{
   public void onTaskDone(List<Task> results);
}

public class Task extends AsyncTask<Void,Void,Void> {
  private List<Task> tasks;
  private TaskListener mListener;

  public Task(TaskListener listener)
  {
     this.mListener = listener;
  }
  protected Void doInBackground(Void... params) {
    .... xml parsing...
    if (mListener != null){
      mListener.onTaskDone(tasks);
    }
  }
}

and when you create the task:

Task task = new Task(this);

letting the class implementing the TaskListener interface.

In this method you provide the task's result to the adapter.

public void onTaskDone(final List<Task> tasks){
        runOnUiThread(new Runnable() {

                @Override
                public void run() {
                      mAdapter = new TaskAdapter(tasks);
                      mTaskRV.setAdapter(mAdapter);
                }
        });


}
Lino
  • 5,084
  • 3
  • 21
  • 39
  • When I add the new code on onTaskDone then onCreateView won't wait for onTaskDone so the View will be emtpy, here is the new onTaskDone code: http://pastebin.com/w1Sr5CnJ – neX Feb 27 '16 at 20:31
0

First let's use this for while which is more clear. And using get text should be better cause it can avoid jumping over a tag or such in other cases.

while (eventType != XmlPullParser.END_DOCUMENT) {
    if (eventType == XmlPullParser.START_TAG) {
        if (xpp.getName().equalsIgnoreCase("name")) {
            tasks.add(new Task(xpp.getText()));
        }
    }
    eventType = xpp.next();
}

And a out that error in List<Task> tasks = task.getTasks(); This should help https://stackoverflow.com/a/218510/2226796

Also I didn't get this part :

Task task = new Task();
new Task().execute();
Community
  • 1
  • 1
Sina R.
  • 1,781
  • 2
  • 19
  • 37
  • I know why you get a NPE, my question was how I can wait for AsyncTask so I don't get it. I use new Task().execte(); to run AsyncTask. – neX Feb 27 '16 at 20:57
  • @neX No idea :| just I hope u find more in link I gave you. U may check it – Sina R. Feb 27 '16 at 21:13