4

How could I change the index value of a json object existing in my QueryUtils file from inside a Fragment?

This part right here: JSONObject currentDay = dayArray.getJSONObject(0);

I want the index value to change for each fragment but couldn't wrap my head around it. I have tried with intents and creating a constructor but failed.

As is right now, the app is 'working' with all fragments displaying the schedule for Monday (JSONObject index 0).

QueryUtils.java

import android.text.TextUtils;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;


public final class QueryUtils {

    private static final String LOG_TAG = QueryUtils.class.getSimpleName();

    //makeHttpRequest constants
    private static final int READ_TIMEOUT = 10000 /* milliseconds */;
    private static final int CONNECT_TIMEOUT = 15000 /* milliseconds */;
    private static final int RESPONSE_CODE = 200 /*everything is OK*/;

    public QueryUtils() {
    }

    public static List<Day> fetchDayData(String requestUrl) {

        URL url = createUrl(requestUrl);

        String jsonResponse = null;
        try {
            jsonResponse = makeHttpRequest(url);
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem making the HTTP request.", e);
        }

        List<Day> days = extractFeatureFromJson(jsonResponse);

        return days;
    }

    private static URL createUrl(String stringUrl) {
        URL url = null;
        try {
            url = new URL(stringUrl);
        } catch (MalformedURLException e) {
            Log.e(LOG_TAG, "Problem building the URL ", e);
        }
        return url;
    }
    private static String makeHttpRequest(URL url) throws IOException {
        String jsonResponse = "";

        if (url == null) {
            return jsonResponse;
        }

        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;

        try {
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setReadTimeout(READ_TIMEOUT);
            urlConnection.setConnectTimeout(CONNECT_TIMEOUT);
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            if (urlConnection.getResponseCode() == RESPONSE_CODE) {
                inputStream = urlConnection.getInputStream();
                jsonResponse = readFromStream(inputStream);
            } else {
                Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Problem retrieving Berceni JSON results.", e);
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return jsonResponse;
    }

    private static String readFromStream(InputStream inputStream) throws IOException {
        StringBuilder output = new StringBuilder();
        if (inputStream != null) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
            BufferedReader reader = new BufferedReader(inputStreamReader);
            String line = reader.readLine();
            while (line != null) {
                output.append(line);
                line = reader.readLine();
            }
        }
        return output.toString();
    }

    private static List<Day> extractFeatureFromJson(String dayJSON) {

        if (TextUtils.isEmpty(dayJSON)) {
            return null;
        }

        List<Day> days = new ArrayList<>();

        //Try to parse
        try {

            JSONObject baseJsonResponse = new JSONObject(dayJSON);

            JSONArray dayArray = baseJsonResponse.getJSONObject("schedule").getJSONArray("day");

            JSONObject currentDay = dayArray.getJSONObject(0);
            JSONArray getClasses = currentDay.getJSONArray("classes");

                for (int j = 0; j < getClasses.length(); j++) {
                    JSONObject currentClass = getClasses.getJSONObject(j);

                     String retrieveCourseTitle = currentClass.getString("class");
                     String retrieveCourseTime = currentClass.getString("time");
                     String retrieveCourseTrainer = currentClass.getString("trainer");
                     String retrieveCourseCancelState = currentClass.getString("canceled");

                     Day day = new Day(retrieveCourseTitle, retrieveCourseTime, retrieveCourseTrainer, retrieveCourseCancelState);
                     days.add(day);
                }

        } catch (JSONException e) {
            // If an error is thrown when executing any of the above statements in the "try" block,
            // catch the exception here, so the app doesn't crash. Print a log message
            // with the message from the exception.
            Log.e("QueryUtils", "Problem parsing JSON results", e);
        }

        return days;
    }

}

And my FragmentAdapter.java

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class FragmentAdapter extends FragmentPagerAdapter {

    private Context mContext;

    public FragmentAdapter(Context context, FragmentManager fm) {
        super(fm);
        mContext = context;
    }

    @Override
    public Fragment getItem(int position) {
        if (position == 0) {
            return new MondayFragment();
        } else if (position == 1) {
            return new ThursdayFragment();
        } else if (position == 2) {
            return new WednesdayFragment();
        } else if (position == 3) {
            return new ThursdayFragment();
        } else if (position == 4) {
            return new FridayFragment();
        } else if (position == 5) {
            return new SaturdayFragment();
        } else {
            return new SundayFragment();
        }
    }

    /**
     * Return the total number of pages.
     */
    @Override
    public int getCount() {
        return 7;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        if (position == 0) {
            return mContext.getString(R.string.monday);
        } else if (position == 1) {
            return mContext.getString(R.string.tuesday);
        } else if (position == 2) {
            return mContext.getString(R.string.wednesday);
        } else if (position == 3) {
            return mContext.getString(R.string.thursday);
        } else if (position == 4) {
            return mContext.getString(R.string.friday);
        } else if (position == 5) {
            return mContext.getString(R.string.saturday);
        }   else {
            return mContext.getString(R.string.sunday);
        }
    }

}

JSON Sample Response

{  
   "schedule":{
      "day":[
         {  
            "id":"Monday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                },
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         }, 
         {  
            "id":"Tuesday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                },
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         }, 
         {  
            "id":"Wednesday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }, 
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         },
         {  
            "id":"Thursday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                },
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         }, 
         {  
            "id":"Friday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                },
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         },
         {  
            "id":"Saturday",
            "classes":[
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }, 
                {
                    "class" : "Class",
                    "time" : "00:00",
                    "trainer" : "Teacher",
                    "canceled" : ""
                }
            ]
         }, 
         {  
            "id":"Sunday",
            "classes":[]
         }
      ]
   }
}
Alin
  • 1,218
  • 5
  • 21
  • 47
  • Show JSON which getting from api – ρяσѕρєя K Sep 19 '17 at 08:34
  • @ρяσѕρєяK Hi, I have updated the question with a JSON sample response from the api. – Alin Sep 19 '17 at 08:39
  • Need to iterate `dayArray` JSONArray to show all days instead of using `0` – ρяσѕρєя K Sep 19 '17 at 08:48
  • @ρяσѕρєяK , Yeah, I had that done the first time but how do I pass each iteration to one of my 7 fragments? I initially wrote a for loop and iterated through all of them but couldn't figure how to pass them on to the corresponding Fragments – Alin Sep 19 '17 at 08:52
  • Use a HashMap with List `HashMap>` now use day id as key and `days` as value and according to day get it from HashMap and pass it to respective Fragment – ρяσѕρєя K Sep 19 '17 at 09:15
  • @ρяσѕρєяK I have no idea on how to do that (right now). I am pretty new to Android sooo, I'll have to dig into that and see how it's done. :D – Alin Sep 19 '17 at 09:22
  • is every "classes" item same? – Sarthak Mittal Sep 21 '17 at 09:33
  • @SarthakMittal No, it's just a sample response. That's where the class name is going to be, the same goes for time, trainer and a boolean for canceled. – Alin Sep 21 '17 at 09:34
  • @Alin Your json parsing code is quite messed up :) The "day" object that you create in your loop should be an array, as classes has multiple items, and that array should be added to "days" – Sarthak Mittal Sep 21 '17 at 09:37
  • @SarthakMittal I have a custom Day class with a DayAdapter that extebds the ArrayAdapter for that :) – Alin Sep 21 '17 at 09:39
  • @Alin I know that :) but you need to differentiate the data for each day, right? :) – Sarthak Mittal Sep 21 '17 at 09:41
  • @SarthakMittal Yes I do. Benjaming's answer was kinda on the right track with what I imagined I would end up. – Alin Sep 21 '17 at 09:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154971/discussion-between-sarthak-mittal-and-alin). – Sarthak Mittal Sep 21 '17 at 09:45

3 Answers3

1

Looking at your POJO this isn't explicitly equal to your JSON.

A Day should be declared as:

class Day {
    String id;
    List<ClassDetail> classes;
}

class ClassDetail {
    //all the details
}

I think you are missconcepting your functions, the follow signature isn't too explicit.

List<Day> extractFeatureFromJson(String dayJSON)

In order to make it become more readable, I propose to change it for:
(You can use a Hashmap as recommended for @ρяσѕρєя):

HashMap<String, ClassDetail> parseScheduleJson(String scheduleJSON)

And the add each ClassDetail to the result

@Nullable
private static Map<String, List<ClassDetail>> parseScheduleJson(String scheduleJSON) {

    if (TextUtils.isEmpty(scheduleJSON)) {
        return null;
    }

    HashMap<String, List<ClassDetail>> result = new HashMap<>();

    try {
        JSONObject baseJsonResponse = new JSONObject(scheduleJSON);
        JSONArray dayArray = baseJsonResponse.getJSONObject("schedule").getJSONArray("day");

        for (int i = 0; i < dayArray.length(); i++) {
            ArrayList<ClassDetail> classes = new ArrayList<>();
            JSONObject currentDay = dayArray.getJSONObject(i);
            for (int j = 0; j < currentDay.getJSONArray("classes").length(); j++) {
                JSONObject currentClass = currentDay.getJSONArray("classes").getJSONObject(j);

                String retrieveCourseTitle = currentClass.getString("class");
                String retrieveCourseTime = currentClass.getString("time");
                String retrieveCourseTrainer = currentClass.getString("trainer");
                String retrieveCourseCancelState = currentClass.getString("canceled");

                classes.add(new ClassDetail(retrieveCourseTitle, retrieveCourseTime, retrieveCourseTrainer, retrieveCourseCancelState));
            }
            result.put(currentDay.getString("id"), classes);
        }

    } catch (JSONException e) {
        // If an error is thrown when executing any of the above statements in the "try" block,
        // catch the exception here, so the app doesn't crash. Print a log message
        // with the message from the exception.
        Log.e("QueryUtils", "Problem parsing JSON results", e);
        return null;
    }

    return result;
}

After this, you can access to your list of classes of the day using:

mymap.get("Monday");
mymap.get("Tuesday");
...
mymap.get("Sunday");

Edit:

IMHO, you have to call your dayloader in your activity, and inject the map result to your FragmentPagerAdapter:

public FragmentAdapter(Context context, FragmentManager fm, Map<String, List<ClassDetail> schedule) {
    super(fm);
    mContext = context;
    mSchedule = schedule;
}

@Override
public Fragment getItem(int position) {
    if (position == 0) {
        return MondayFragment.newInstance(mSchedule.get("Monday"));
    //...
    //same for all conditions
    //...
    } else {
        return SundayFragment.newInstance(mSchedule.get("Sunday"));
    }
}

After that when using newIntance pattern you can declare your fragments as:

private List<ClassDetail> mClasses;

public static MondayClassDetailFragment newInstance(ArrayList<ClassDetail> classes){
    MondayClassDetailFragment myFragment = new MondayClassDetailFragment();

    Bundle args = new Bundle();
    args.putParcelableArrayList("classes", classes);
    myFragment.setArguments(args);

    return myFragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mClasses = getArguments().getParcelableArrayList("classes");
}

PS: Making http request and parsing a json manually at these days is a waste of energy. I recommend you to take a look to libraries to do this, in particulary to retrofit who is widely used and very well documented.

crgarridos
  • 8,758
  • 3
  • 49
  • 61
  • Hello @crgarridos , I will dig into it and see if I can make all the required changes without error. I deliberately chose to manually parse the json and make the http request because I am at the learning stage and want to understand how it all works and not rely solely on libraries. I never used HashMap before and don't actually know how to handle **mymap.get("Monday");** in my particular fragment.. – Alin Sep 21 '17 at 10:09
  • I am awarding you the +100 rep cause your answer would take me there. But I found my own solution that for my case, worked best. (see my answer) Cheers, thanks! – Alin Sep 22 '17 at 15:40
  • Thanks for it, but I didn't consider that an API change was the solution( it not always feasible), Given the constraint in your question, I did the best approach. Happy you solved :) – crgarridos Sep 22 '17 at 16:12
  • I initially didn't want to change the API I created cause I wanted to learn more but from what I learned from the Android Basics Nanodegree isn't enough to cover everything I needed and I tried doing things the way I learned they should be done and I tried to stick to what I learned as much as possible. I thought I could achieve this easier by defining a public constructor and calling it in the Fragments but it was more than I wanted to deal with right now. Therefore I came up with another solution. You couldn't've known I could change the API as well and made do with what you had. Thank you! – Alin Sep 22 '17 at 17:47
0

I'm not sure of this because I've never used FragmentPagerAdapter, but I suppose it works as any Adapter, conceptually.

What I am noticing in your code is that in your code (see comment)

private static List<Day> extractFeatureFromJson(String dayJSON) {

    if (TextUtils.isEmpty(dayJSON)) {
        return null;
    }

    List<Day> days = new ArrayList<>();

    //Try to parse
    try {

        JSONObject baseJsonResponse = new JSONObject(dayJSON);

        JSONArray dayArray = baseJsonResponse.getJSONObject("schedule").getJSONArray("day");

        JSONObject currentDay = dayArray.getJSONObject(0); //<<<<<<HERE
        JSONArray getClasses = currentDay.getJSONArray("classes");

            for (int j = 0; j < getClasses.length(); j++) {
                JSONObject currentClass = getClasses.getJSONObject(j);

                 String retrieveCourseTitle = currentClass.getString("class");
                 String retrieveCourseTime = currentClass.getString("time");
                 String retrieveCourseTrainer = currentClass.getString("trainer");
                 String retrieveCourseCancelState = currentClass.getString("canceled");

                 Day day = new Day(retrieveCourseTitle, retrieveCourseTime, retrieveCourseTrainer, retrieveCourseCancelState);
                 days.add(day);
            }

    } catch (JSONException e) {
        // If an error is thrown when executing any of the above statements in the "try" block,
        // catch the exception here, so the app doesn't crash. Print a log message
        // with the message from the exception.
        Log.e("QueryUtils", "Problem parsing JSON results", e);
    }

    return days;
}

You are doing the "extraction" only for JSONObject currentDay = dayArray.getJSONObject(0);

This means your List<Day> days will have only one Day in it, that is current day. Supposing you're feeding this List to your adapter, only a Day is found, hence nothing is changing.

I suggest you iterate through ALL the days, appending each day to the List with something like this:

try{
    JSONObject baseJsonResponse = new JSONObject(dayJSON);
    JSONArray dayArray = baseJsonResponse.getJSONObject("schedule").getJSONArray("day");
    for (int i = 0; i<dayArray.length();i++){
        JSONObject currentDay = dayArray.getJSONObject(i);
        //the rest
    }
}catch(JSONException e){
    //etc
}
magicleon94
  • 4,887
  • 2
  • 24
  • 53
  • Thank you for your answer. The issue here is that this will add the entire JSON response in every fragment. What I want is to have the JSONObject with index 0 (monday) in the MondayFragment, JSONObject with index 1 (tuesday) in the TuesdayFragment and so on. – Alin Sep 21 '17 at 09:37
  • Well what you're saying makes me think that I thought it right then. In your for loop you add all the classes but you work on day 0. Am I getting it right if I say that you need do to this for day 0,1,2 and so on? – magicleon94 Sep 21 '17 at 09:39
  • Your code takes day 0 and adds to `days` the same day but with a different class. Each fragment displays a day, right? My way is not correct but maybe I understood something. Just tell me if I'm on your same line of thought: one fragment per day, different classes each day – magicleon94 Sep 21 '17 at 09:41
  • Yes, I need this for day 0 to 6 but looping and displaying them wasn't an issue, sending each day to it's corresponding fragment was. Do you have an idea on how to do that? Benjamin kinda got on the right track. – Alin Sep 21 '17 at 09:42
  • Can you share the part of the code where you set the data for the adapter and link them to the pager? I'm still unsure about how the whole process goes – magicleon94 Sep 21 '17 at 09:45
  • Will add the custom Day class, the DayAdapter and DayLoader in a sec. – Alin Sep 21 '17 at 09:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154973/discussion-between-magicleon-and-alin). – magicleon94 Sep 21 '17 at 09:56
0

While @crgarridos 's answer would work, I kept thinking of a faster and easier way of achieving my goal with minimum code modifications so:

I ended up modifying my JSON API and creating query url's for the id key so that I could query like this: URL?id=monday.

Next up I simply needed to add a URI builder and appendQueryParameter(key, value); for each of my fragments.

Alin
  • 1,218
  • 5
  • 21
  • 47