How to send multiple items of recyclerview from one activity to another - android

I have an ArrayList of type Course. Course has id ( string ), name ( string ).
I want to display a list of courses on one screen. Give the user option to select multiple courses which they have completed and send these courses to next activity.
I am able to MultiSelect courses in a RecyclerView. But unable to send the data to another activity.

you can convert the data to JSON string & pass easily between activities using intent bundles...
create extension functions like these
// convert safely from json to class
fun <T> String.fromSafeJson(classOfT: Class<T>): T? {
return try {
Gson().fromJson(this, classOfT)
} catch (e: Exception) {
null
}
}
// convert any object to json
fun Any.toJson(): String {
return Gson().toJson(this)
}
after that you can convert any list of any type using yourList.toJson(), send it via bundle and in next activity get it from bundle and parse using stringName.fromSafeJson(YourListType)
remember to add Gson library... use can use the following
implementation 'com.google.code.gson:gson:2.9.0'

Related

How do I merge/map two json response that has a common key/field and show it in recyclerview android and search also using some kotlin operator?

What is the best way to do the following:
I have one json like:
{
"restaurants":[
{
"id":1,
"name":"Chinese Food",
"neighborhood":"New york",
"photograph":"abc.jpg",
"cuisine_type":"Chinese"
}, ..]
and second json response is
{ "menu":[
{
"restaurantId":1,
"allcategories":[
{
"id":"100",
"name":"Noodles",
"menu_items":[
{
"id":"800",
"name":"Hakka noodles",
"description":"Tasty hakka noodles",
"price":"350.00",
},
{
"id":"900",
"name":"Shezwan Hakka noodles",
"description":"Shezwan sauce spicy hakka noodles",
"price":"750.00",
}
]
}, ...],...}]}
I want to show all restaurants from first json response in recyclerview and along with it I want to show their respective menus also in the same card using the second response, where restaurant id is common in both the responses.
I have thought of couple of ways of doing it, like adding categoies and menu items in the first response/data class itself and then populating the UI from adapter or maybe using the common key in both the response as hashmap key and storing entire category from second response for each restaurant as value in hashmap and then in onbindViewholder finding category and then menu-items from second response object.
But this all seems little unclean, and i was thinking if there was a simpler way to achieve this using some kotlin operators. Can anyone suggest anything simpler and better?
P.S
I want to implement search filter also later, so I am looking for a solution in which i can search also between both the responses, like restaurant name from first response and menuitems from second response, and then my recyclerview will show the searched items.
Thanks in advance.
what I have done write now (using common key as Hashmap key) looks like this:
override fun onBindViewHolder(holder: RestaurantAdapter.RestViewHolder, position: Int) {
getCategoryList(restList.get(position).id)?.forEach {
it?.let {
holder.binding.tvMenuItem.text= "${it?.menuItems}"
}
}
}
fun getCategoryList(restId:Int?):ArrayList<Category?>?{
return menuMap.get(restId)?.categories
}
You can use
.filter { <filter predicate> } that returns a new list of items based on the condition you provided
map { } that that returns a list of items, where each item is transformed or modified from what you provided in the map function
You can find more Kotlin collection operations from the following links
https://github.com/benct/kotlin-cheat-sheet
https://medium.com/mobile-app-development-publication/kotlin-collection-functions-cheat-sheet-975371a96c4b
You can also perform a series of chained operations

How to remove an item from repeated list in Android proto DataStore?

Here is the proto file with the definition for a list of strings.
message MyMessages {
repeated string message = 1;
}
Here is the function for removing a message from the repeated message list.
suspend fun removeMsg(msg : String) {
myMessagesStore.updateData { myMessages ->
val existingMessages = myMessages.toBuilder().messageList;
if (existingMessages.contains(msg)) {
existingMessages.remove(msg)
myMessages.toBuilder().clear().addAllMessage(existingMessages).build()
} else {
myMessages
}
}
}
When the above code runs, it crashed on existingMessages.remove(msg) with the error:
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.remove
existingMessages is a MutableList which contains the remove function, why is this crashing on this and what's the proper way to remove an item from a repeated list item in proto DataStore?
Updates:
existingMessages is
/**
* <code>repeated string message = 1;</code>
* #return A list containing the message.
*/
#java.lang.Override
public java.util.List<java.lang.String>
getMessageList() {
return java.util.Collections.unmodifiableList(
instance.getMessageList());
}
It looks like the generated class from proto is making the repeated list unmodfiableList. Then my question is why there isn't a myMessages.toBuilder().removeMessage(newMessage) function from the generated class similar to the addMessage function such as this:
myMessages.toBuilder().addMessage(newMessage)
Could you please post the exact data type of existingMessages.
I am not an expert in proto DataStore, so please correct me incase I am wrong.
As per the exception message, there could be few main reason behind the crash:
The existingMessages is immutable list. As per the exception, we can see that the name of the collection is java.util.Collections$UnmodifiableCollection.
The existingMessages is a custom mutable list, which haven't implemented the #remove function.
To fix this, you can choose one of the following approach based on your guidelines:
Update the type of messageList in Builder class as MutableList for other external classes.
In case you are using custom implementation of list and the #remove is not implemented, please implement it.
In case you can't change the return type of messageList, simply use #filter method to copy and skip the required message as follow:
existingMessages.filter { it != msg }

Populate a list in Kotlin with a for loop

It's been a while that I just started to learn how to develop in Kotlin.
There is this thing that I am working on, I am trying to parse a list into another type of list. Basically they are the same thing but with different names. But when I try to populate the new list with the data that I get from the list given as parameter in the function the list only gets populated with the first object.
Here is my function:
fun convertRoomClass(course: List<Course>) : List<Courses> {
lateinit var list : List<Courses>
course.forEach {
val id = it.pathID
val name = it.pathName
val desc = it.pathDescription
val crs : Courses = Courses(id, name!!, desc!!)
list = listOf(crs)
}
return list
}
The error in your code is that you are making a list in every iteration of the loop. You should make the list first and then add every item from the loop to it!
fun convertRoomClass(courses: List<Course>) : List<AnotherCourseClass> {
val newList = mutableListOf<AnotherCourseClass>()
courses.forEach {
newList += AnotherCourseClass(it.pathID, it.pathName, it.pathDescription)
}
return newList
}
A better solution is to use the map function
fun convertRoomClass(courses: List<Course>) = courses.map {
AnotherCourseClass(it.pathID, it. pathName, it.pathDescription)
}
You might be looking for Kotlin Map
Example:
course.map { Courses(it.pathID, it.pathName,it.pathDescription) }
You're getting the list with only on object, cause the function listOf(crs) returns a list of all objects that are passed as a parameters. Saying the same thing in Java you're doing something like this:
for (course: Courses) {
Course course = new Course(...);
List<Course> list = new ArrayList<>();
list.add(course);
return list;
}
As you can see the it created new list with a single object per iteration.
What you're trying to achieve, can be done with operator map{...} which simply transforms every object in the initial list using code passed inside map and returns list of transformed objects
course.map{ Courses(...) }
Also, I've noticed that you're using the !! operator when creating a Courses object. Probably because the Course can have nullable name, while Courses can't. I'm considering this as a bad practice, cause in this case you're saying
Please throw an Exception if the name is null.
I think that a much better approach is to provide an alternative, like:
val name = course.name ?: "default", saying
Please use name or "default" if the name is null.
or skip objects without name, or any other approach that suits your situation.
You could use MutableList instead of List. That enable you to append new element at the end of your list instead of replace the entire list by doing : list = listOf(crs)
So replace the type of your var lateinit var list : List<Courses> by lateinit var list : MutableList<Courses> then replace list = listOf(crs) by list.add(crs)
Hope it helps and have fun :)

Convert list to another list using RxJava

The need is a little strange. I want to convert a list to a new list. For example, convert List<Android> to List<AndroidWrapper>.
class AndroidWrapper has two fields.
public class AndroidWrapper {
private Android mAndroid;
private String mAvatarUrl;
public AndroidWrapper(Android android, String avatarUrl) {
this.mAndroid = android;
this.mAvatarUrl = avatarUrl;
}
}
The field mAvatar is related to mAndroid field and it can be fetched from remote server.
Observable<String> fetchAvatarUrl(Android android)
So how can do this using RxJava2?
Turn your list into an Observable, flatMap the dependent call onto it, create the final object type and collect it into a list:
Observable.fromIterable(androids)
.flatMap(android ->
fetchAvatarUrl(android)
// go into a backgroud thread
.subscribeOn(Schedulers.io())
// combine the result with the original value
.map(url -> new AndroidWrapper(android, url))
// limit the maximum concurrent fetch calls
, 1
)
.toList();

Parcelable array passed with kotlin is emitting last item

I'm trying to pass an array to my activity, but for some odd reason the last item of the array is passed as null
Here's the code
Helper function to create the intent:
#JvmStatic
fun newTutorProfile(context: Context, webinars: List<Webinar>): Intent {
val tutorActivity = Intent(context, TutorWebinarProfileActivity::class.java)
tutorActivity.putExtra(WEBINARS_ARG, webinars.toTypedArray()) // Array contains two valid elements
return tutorActivity
}
Extracting the array from the intent:
webinars = intent.getParcelableArrayExtra(WEBINARS_ARG).map { it as Webinar } // array contains two elemnts but the second one is now null

Categories

Resources