How to hide json object in recyclerview based on condition? - java

I have one json array in array list I need show one object as count and one as text view, while going to filter the object I'm not able to find count view and display view, I search for hash map but it does not work, my question i can i add two array list in one recyclerview adapter one for view and one for count in same view.
Edit: after researching about that I come to know I need to hide object if it is a match with id but I could not found to display and hide content base on condition in recyclerview any solution?
#Override
public void onBindViewHolder(#NonNull DiscussingAdapter.DiscussionView holder, int position) {
HashMap<String, List<Result>> hashMap = new HashMap<String, List<Result>>();
Result result = discussionsList.get(position);
//discussionsList.get(position);
List<Result> filterList = discussionsList.stream()
.filter(p -> p.getParentCommentID()==null).collect(Collectors.toList());
Log.d("filterList",filterList.toString());
for (int counter = 0; counter < filterList.size(); counter++) {
holder.tvHeader.setText(filterList.get(counter).getTitle());
holder.tvDetail.setText(Utils.html2text(filterList.get(counter).getComment()));
holder.tvViewReply.setText("Reply");
holder.tvUser.setText("By " + filterList.get(counter).getAuthor().getTitle());
String DateofReceipt = filterList.get(counter).getCreated();
String date = DateofReceipt.split("T", 0)[0];
String date_before = date;
String date_after = Utils.date(date_before);
holder.tvDate.setText(date_after);
}
Map<String, Integer> commentsCountMap = new HashMap<>();
for(Result res : discussionsList) {
String parentCommentId = res.getParentCommentID();
// If the Result has a parent comment
if(parentCommentId != null) {
// get the count for this parent comment (default to 0)
int nbCommentsForParent = commentsCountMap.getOrDefault(parentCommentId, 0);
// increment the count
nbCommentsForParent++;
// Update the Map with the new count
commentsCountMap.put(parentCommentId, nbCommentsForParent);
}
}
for(Map.Entry<String,Integer> cCount : commentsCountMap.entrySet()){
holder.tvViewReply.setText(String .valueOf(cCount.getValue())+" Reply");
}}
Json object generated is as below
{
"d": {
"results": [
{
"__metadata": {
"id": "e7433825-6771-4f5e-96c7-c4d2674d7764",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "f064775c-6161-4bdb-9f4d-8bc6a898d218",
"type": "SP.Data.UserInfoItem"
},
"Title": "Submitter1"
},
"Id": 1501,
"ID": 1501,
"Title": null,
"Created": "2019-06-06T04:15:17Z",
"ParentCommentID": "1439",
"Comment": "<div class=\"ExternalClass8C333A77B6564A53BED74CA1BA2D2A10\">
reply add for 009</div>",
"CommentType": null,
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Customer"
},
{
"__metadata": {
"id": "e92f708f-93dc-4587-8c4f-5518ed24f360",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "209d2d9a-bb07-4064-aaa0-231ad881a80f",
"type": "SP.Data.UserInfoItem"
},
"Title": "Submitter1"
},
"Id": 1500,
"ID": 1500,
"Title": null,
"Created": "2019-06-06T04:14:55Z",
"ParentCommentID": "1439",
"Comment": "<div class=\"ExternalClass44B1A0BB4D314C57BEE20141BFF10491\">comment add for 009</div>",
"CommentType": null,
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Customer"
},
{
"__metadata": {
"id": "ec112002-3132-4bc1-8f85-03fbd9fda11d",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "6e8ecb1d-4deb-4168-a8b4-a725abf8002a",
"type": "SP.Data.UserInfoItem"
},
"Title": "Sarada Devi Potti"
},
"Id": 1439,
"ID": 1439,
"Title": "Canceled",
"Created": "2019-06-03T09:32:34Z",
"ParentCommentID": null,
"Comment": "<div class=\"ExternalClass5E1BFEDC348C43719AD940E644E0E0B6\">sdaeadfasdf</div>",
"CommentType": "Public",
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Budget Analyst"
}
]
}
}
In Above Json response if object is Comment I want to display content but if it is a reply I need to display count base on id match any solution?

You can achieve this in a simple way first pass both the list to your adapter
then return the total size
#Override
public int getItemCount() {
return mList.size() + mList1.size();
}
Now for onBindViewHolder for example you want to display mList first then
#Override
public void onBindViewHolder(#NonNull DiscussingAdapter.DiscussionView holder, int position) {
if(position < mList.size()){
// Load the data from mList
holder.tvName.setText(mList.get(position).getName())
}else{
//For getting Data from secondList
holder.tvName.setText(mList1.get(position-mList.getSize()).getName())
// Now you will get data from second List
}
}

I am not sure I understand you fully. However, In my opinion, you can create a model class and keep two variables there.
public class Demo {
private int count;
private int value;
public Demo(int count, int value) {
this.count = count;
this.value = value;
}
}
Then, you can create an ArrayList of that model class and pass it to RecyclerView adapter.
ArrayList<Demo> demos = new ArrayList<>();
Demo firstObject = new Demo(1, 10);
demos.add(firstObject);
Demo secondObject = new Demo(2, 11);
demos.add(secondObject);
Demo thirdObject = new Demo(3, 12);
demos.add(thirdObject);
Feel free to ask if I'm not clear or anything else.

Related

JAVA - Sort Array of Json by multiple values while preserving previous sort order

I have this json and I want to be able to sort it by multiple field values of different types while retaining the previous sort order.
{
"code": "1603",
"description": "",
"score": 10,
"max": 100,
"effts": "2021-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "INACTIVE"
},
{
"code": "1604",
"description": "",
"score": 10,
"max": 100,
"effts": "2020-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "INACTIVE"
},
{
"code": "1600",
"description": "",
"score": 10,
"max": 100,
"effts": "2021-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
},
{
"code": "1606",
"description": "",
"score": 10,
"max": 100,
"effts": "2022-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
},
{
"code": "1601",
"description": "",
"score": 10,
"max": 100,
"effts": "2020-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
}
]
The fields by which I should decide to sort it are given through another json:
{
"id": 1,
"field": "status",
"type": "string",
"sortMode": "ASC"
},
{
"id": 2,
"field": "expDate",
"type": "string",
"sortMode": "ASC"
}
]
I managed to achieve this by converting the json array to a list of Hashmap<String,Object>
and wrote a custom comparator. The problem is when I sort by status in ASC order which puts the ACTIVE entries at top, I don't want this order to get messed when I choose to sort it by another field like expDate for example.
Here is my code:
public String sort() throws JsonProcessingException {
List<TreeMap<String, String>> sortOrder = readSortOrder(sortOrderJson);
List<HashMap<String, Object>> payLoad = readPayLoad(payloadJson);
ObjectMapper objectMapper = new ObjectMapper();
if (sortOrder.size() > 1) {
for (TreeMap<String, String> map : sortOrder) {
if (map.get(Constants.SORT_MODE).equals(SortOrder.DSC.toString())) {
payLoad.sort(new MapComparator(map.get(Constants.FIELD)).reversed());
} else {
payLoad.sort(new MapComparator(map.get(Constants.FIELD)));
}
}
}
return objectMapper.writeValueAsString(payLoad);
}
public List<HashMap<String, Object>> readPayLoad(String jsonInput) {
ObjectMapper mapper = new ObjectMapper();
List<HashMap<String, Object>> jsonList = new ArrayList<>();
try {
HashMap[] payLoadDTOS = mapper.readValue(jsonInput, HashMap[].class);
jsonList = Arrays.asList(payLoadDTOS);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonList;
}
public List<TreeMap<String, String>> readSortOrder(String sortOrder) {
final ObjectMapper objectMapper = new ObjectMapper();
List<TreeMap<String, String>> jsonList = new ArrayList<>();
try {
TreeMap[] sortOrderDTOS = objectMapper.readValue(sortOrder, TreeMap[].class);
jsonList = Arrays.asList(sortOrderDTOS);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonList;
}
And this as comparator:
public class MapComparator implements Comparator<Map<String, Object>> {
private final String key;
public MapComparator(String key) {
this.key = key;
}
#Override
public int compare(Map<String, Object> one, Map<String, Object> two) {
Object first = one.get(key);
Object second = two.get(key);
if (first instanceof String && second instanceof String) {
if ((isValidDate((String) first) && isValidDate((String) second))
|| (isValidDateTime((String) first) && isValidDateTime((String) second))) {
return DateTimeComparator.getInstance().compare(first, second);
} else {
return ((String) first).compareTo((String) second);
}
} else if (first instanceof Integer && second instanceof Integer) {
return ((Integer) first).compareTo((Integer) second);
}
return 0;
}
}
I think I should separate say ACTIVE and INACTIVE in two other collections and sort each then, but the fields by which I may conduct the separation could be dynamic and may change each time. How can I algorithmically handle this?
A sorting algorithm that preserves the existing order on same-valued entries is called stable. In Java, you can consult the API whether a given sorting function is guaranteed to be stable, such as Arrays.sort.
The typical way of sorting using multiple keys is to sort the entries sequentially with a stable sorting algorithm in reverse order of keys.
For example, if you want to order by first name first and last name second, you would first sort by last name and then by first name.
You also need to make sure that the data structure you use preserves the order of insertion, for example a Set or Map may not preserve that.

Parsing nested JSON from a server

I am working on an android project that parses JSON from a file on a server and converting the data into java objects to display the data using text views.
The JSON file that I am parsing is based on a collection of books. Within each book entry is an author which has nested child elements for the last and first name of that author. Some entries can have multiple authors.
JSON file:
{
"bib": {
"book": [
{
"year": "1994",
"title": "TCP/IP Illustrated",
"author": {
"last": "Stevens",
"first": "W."
},
"publisher": "Addison-Wesley",
"price": "65.95"
},
{
"year": "1992",
"title": "Advanced Programming in the Unix environment",
"author": {
"last": "Stevens",
"first": "W."
},
"publisher": "Addison-Wesley",
"price": "65.95"
},
{
"year": "2000",
"title": "Data on the Web",
"author": [
{
"last": "Abiteboul",
"first": "Serge"
},
{
"last": "Buneman",
"first": "Peter"
},
{
"last": "Suciu",
"first": "Dan"
}
],
"publisher": "Morgan Kaufmann Puslishers",
"price": "39.95"
},
{
"year": "2012",
"title": "Professional Android 4 application development",
"author": {
"last": "Meier",
"first": "Reto"
},
"publisher": "ndianapolis : John Wiley and Sons",
"price": "33.47"
},
{
"year": "2017",
"title": "Java Programming for Beginners: Learn the fundamentals of programming with Java",
"author": {
"last": "Lassoff",
"first": "Mark"
},
"publisher": "Packt Publishing",
"price": "23.99"
},
{
"year": "2005",
"title": "Head First Java",
"author": [
{
"last": "Sierra",
"first": "Kathy"
},
{
"last": "Bates",
"first": "Bert"
},
],
"publisher": "MO'Reilly Media; 2 edition",
"price": "21.25"
},
{
"year": "2013",
"title": "XML for Dummies",
"author": {
"last": "Tittel",
"first": "Ed"
},
"publisher": "Wiley; 4th edition",
"price": "14.99"
},
{
"year": "2019",
"title": "Java XML and JSON: Document Processing for Java SE",
"author": {
"last": "Friesen",
"first": "Jeff"
},
"publisher": "Apress; 2nd ed. edition",
"price": "65.95"
},
{
"year": "2016",
"title": "Java Programming for Android Developers For Dummies (For Dummies (Computers))",
"author": {
"last": "Burd",
"first": "Barry A."
},
"publisher": "John Wiley and Sons; 2nd edition",
"price": "16.99"
}
]
}
}
JSON Parser:
private class parseJSON extends AsyncTask<Void, Void, List<Book>> {
private final String TAG = parseJSON.class.getSimpleName();
#Override
protected List<Book> doInBackground(Void... voids) {
Log.i(TAG, "Start Async to get books.");
ArrayList<Book> bookArray = new ArrayList<>(0);
String jsonUrl = getApplication().getString(R.string.json_feed);
HttpHandler httpHandler = new HttpHandler();
String jsonString = httpHandler.makeJsonServiceCall(jsonUrl);
Log.i(TAG, "Response from url: " + jsonString);
if( jsonString != null) {
try {
JSONObject root = new JSONObject(jsonString);
// Get JSON array node.
JSONArray books = root.getJSONObject("bib").getJSONArray("book");
// Looping through all the books.
for (int i = 0; i < books.length(); i++) {
JSONObject jsonBook = books.getJSONObject(i);
String year = jsonBook.getString("year");
String title = jsonBook.getString("title");
String author = jsonBook.getString("author");
String publisher = jsonBook.getString("publisher");
String price = "£" + jsonBook.getString("price");
final Book bookObject = new Book(year, title, author, publisher, price);
//Add the new books to our result array.
bookArray.add(bookObject);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return bookArray;
}
#Override
protected void onPostExecute( List<Book> books) {
super.onPostExecute(books);
Log.e(TAG, "Populate UI recycler view with json converted data.");
bookList.setValue(books);
}
}
What is the best way I can accomplish this?
Use Gson by google, in your gradle add:
implementation 'com.google.code.gson:gson:2.8.6'
and you get it like:
Book bookObject = new Gson().fromJson("json", Book.class);

how to make count similar id object in list and display in recyclerview?

I have a JSON array, in that I need to make match count using ParentCommentID and parse data into recyclerview using text view while counting i get number count only one position and same for other item also, any help.
{
"d": {
"results": [
{
"__metadata": {
"id": "e7433825-6771-4f5e-96c7-c4d2674d7764",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "f064775c-6161-4bdb-9f4d-8bc6a898d218",
"type": "SP.Data.UserInfoItem"
},
"Title": "Submitter1"
},
"Id": 1501,
"ID": 1501,
"Title": null,
"Created": "2019-06-06T04:15:17Z",
"ParentCommentID": "1439",
"Comment": "<div class=\"ExternalClass8C333A77B6564A53BED74CA1BA2D2A10\">
reply add for 009</div>",
"CommentType": null,
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Customer"
},
{
"__metadata": {
"id": "e92f708f-93dc-4587-8c4f-5518ed24f360",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "209d2d9a-bb07-4064-aaa0-231ad881a80f",
"type": "SP.Data.UserInfoItem"
},
"Title": "Submitter1"
},
"Id": 1500,
"ID": 1500,
"Title": null,
"Created": "2019-06-06T04:14:55Z",
"ParentCommentID": "1439",
"Comment": "<div class=\"ExternalClass44B1A0BB4D314C57BEE20141BFF10491\">comment add for 009</div>",
"CommentType": null,
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Customer"
},
{
"__metadata": {
"id": "ec112002-3132-4bc1-8f85-03fbd9fda11d",
"uri": "",
"etag": "\"2\"",
"type": "SP.Data.InquiryDiscussionsListListItem"
},
"Author": {
"__metadata": {
"id": "6e8ecb1d-4deb-4168-a8b4-a725abf8002a",
"type": "SP.Data.UserInfoItem"
},
"Title": "Sarada Devi Potti"
},
"Id": 1439,
"ID": 1439,
"Title": "Canceled",
"Created": "2019-06-03T09:32:34Z",
"ParentCommentID": null,
"Comment": "<div class=\"ExternalClass5E1BFEDC348C43719AD940E644E0E0B6\">sdaeadfasdf</div>",
"CommentType": "Public",
"CommentDocumentName": null,
"AppID": "1083",
"Role": "Budget Analyst"
}
]
}
}
My code is onbind method:
Map<String, Integer> commentsCountMap = new HashMap<>();
for(Result res : discussionsList) {
String parentCommentId = res.getParentCommentID();
// If the MyDocsResult has a parent comment
if(parentCommentId != null) {
// get the count for this parent comment (default to 0)
int nbCommentsForParent = commentsCountMap.getOrDefault(parentCommentId, 0);
// increment the count
nbCommentsForParent++;
// Update the Map with the new count
commentsCountMap.put(parentCommentId, nbCommentsForParent);
System.out.println(commentsCountMap);
Log.d("Count:",commentsCountMap.toString());
}
}
for example id 1439, having two ParentCommentID, so in that case for id 1439 there should be a count of two comments, I tried to use for in my
recyclerview adapter but its dose not work.
I think you need to run through the list of Results and when when you find a Result that has a parent comment, then you go in the map, get the parent comment, increment its count by one and stick it back in the Map:
Assuming your Result class is something like this:
class Result {
private String id;
private String parentCommentID;
public Result(String id, String parentCommentID) {
this.id = id;
this.parentCommentID = parentCommentID;
}
// GETTERS/SETTERS
}
And you have a discussion list with 3 Results
discussionsList = Arrays.asList(
new Result("1439", null),
new Result("1500", "1439"),
new Result("1801", "1439")
);
Like your case, 1439 has no parent and 1500 and 1501 both have 1439 as parent
Then you can do this kind of thing:
Map<String, Integer> commentsCountMap = new HashMap<>();
// Loop through the discussion Map
for(Result res : discussionsList) {
String parentCommentId = res.getParentCommentID();
// If the Result has a parent comment
if(parentCommentId != null) {
// get the count for this parent comment (default to 0)
int nbCommentsForParent = commentsCountMap.getOrDefault(parentCommentId, 0);
// increment the count
nbCommentsForParent++;
// Update the Map with the new count
commentsCountMap.put(parentCommentId, nbCommentsForParent);
}
}
System.out.println(commentsCountMap);
This outputs
{1439=2}

how to parse this in android with json

I want to parse this json in android. Can you help me how to parse, if i need to start from head to parse or from results for this I don't know. Can you help me
{
"head":
{
"link": [],
"vars": ["city", "country"]
},
"results":
{
"distinct": false,
"ordered": true,
"bindings":
[
{
"city":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Ferizaj"
} ,
"country":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Kosovo"
}
}
]
}
}
Okay, first of all the JSON string you've given is invalid. I've written my answer based on the correct version of the JSON string that you have provided
{
"head":
{
"link": [],
"vars": ["city", "country"]
},
"results":
{
"distinct": false,
"ordered": true,
"bindings":
[
{
"city":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Ferizaj"
} ,
"country":
{
"type": "uri",
"value": "http://dbpedia.org/resource/Kosovo"
}
}
]
}
}
Now, to get the "values", you'll need to do this.
JSONObject jsonObject = new JSONObject(response);
JSONObject results = jsonObject.getJSONObject("results");
JSONArray bindings = results.getJSONArray("bindings");
for (int i = 0; i < bindings.length(); i++) {
JSONObject binding = bindings.getJSONObject(i);
JSONObject city = binding.getJSONObject("city");
// Get value in city
String cityValue = city.getString("value");
Log.d("CITY", cityValue);
JSONObject country = binding.getJSONObject("country");
// Get value in country
String countryValue = country.getString("value");
Log.d("COUNTRY", countryValue);
}

Finding deeply nested key/value in JSON

Suppose I have a JSON array like this:
[
{
"id": "429d30a1-9364-4d9a-92e0-a17e00b3afba",
"children": [],
"parentid": "",
"name": "Expo Demo"
},
{
"id": "f80f1034-9110-4349-93d8-a17e00c9c317",
"children":
[
{
"id":"b60f2c1d-368b-42c4-b0b2-a1850073e1fe",
"children":[],
"parentid":"f80f1034-9110-4349-93d8-a17e00c9c317",
"name":"Tank"
}
],
"parentid": "",
"name": "Fishtank"
},
{
"id": "fc8b0697-9406-4bf0-b79c-a185007380b8",
"children": [
{
"id":"5ac52894-4cb6-46c2-a05a-a18500739193",
"children":[
{
"id": "facb264c-0577-4627-94a1-a1850073c270",
"children":[
{
"id":"720472b5-189e-47f1-97a5-a18500a1b7e9",
"children":[],
"parentid":"facb264c-0577-4627-94a1-a1850073c270",
"name":"ubSubSub"
}],
"parentid": "5ac52894-4cb6-46c2-a05a-a18500739193",
"name": "Sub-Sub1"
}],
"parentid":"fc8b0697-9406-4bf0-b79c-a185007380b8", "name":"Sub"
},
{
"id":"4d024610-a39b-49ce-8581-a18500739a75",
"children":[],
"parentid":"fc8b0697-9406-4bf0-b79c-a185007380b8",
"name":"Sub2"
}
],
"parentid": "",
"name": "Herman"
},
{
"id": "a5b140c9-9987-4e6d-a883-a18c00726883",
"children": [
{
"id":"fe103303-fd5e-4cd6-81a0-a18c00733737",
"children":[],
"parentid":"a5b140c9-9987-4e6d-a883-a18c00726883",
"name":"Contains Spaces"
}],
"parentid": "",
"name": "Kiosk"
}
]
No I want to find a certain object based on a id and once I have that, I need its children and all its childrends children
So lets say i want to find the element with an id if 4d024610-a39b-49ce-8581-a18500739a75
That should find the Element Sub2
And now it should produce all the child elements ids witch will be:
facb264c-0577-4627-94a1-a1850073c270
720472b5-189e-47f1-97a5-a18500a1b7e9
Let say I would do
findElementsChildren("4d024610-a39b-49ce-8581-a18500739a75")
So i guess its two parts, first find the "parent" element. Then find its childrends childrends children etc..
Any help would be much appreciated!
You can use recursion to solve the problem of unlimited nesting. With Gson, it would be something like the following code snippet (not tested). Other libraries will provide structures as JsonElement as well.
private JsonElement findElementsChildren(JsonElement element, String id) {
if(element.isJsonObject()) {
JsonObject jsonObject = element.getAsJsonObject();
if(id.equals(jsonObject.get("id").getAsString())) {
return jsonObject.get("children");
} else {
return findElementsChildren(element.get("children").getAsJsonArray(), id);
}
} else if(element.isJsonArray()) {
JsonArray jsonArray = element.getAsJsonArray();
for (JsonElement childElement : jsonArray) {
JsonElement result = findElementsChildren(childElement, id);
if(result != null) {
return result;
}
}
}
return null;
}
Based on Stefan Jansen's answer I made some changes and this is what I have now:
nestedChildren declared globaly, and before the children are searched reset to new ArrayList()
private void findAllChild(JSONArray array) throws JSONException {
for ( int i=0;i<array.length();i++ ) {
JSONObject json = array.getJSONObject(i);
JSONArray json_array = new JSONArray(json.getString("children"));
nestedChildren.add(json.getString("id"));
if ( json_array.length() > 0 ) {
findAllChild(json_array);
}
}
}
This assumes it is all Arrays, witch in my case it is

Categories