Mark M. | has entered the room |
Apr 16 | 8:25 AM |
Mark M. | turned on guest access |
Apr 16 | 8:30 AM |
Mohd A. | has entered the room |
Mark M. |
hello, Mohd!
|
Mark M. |
how can I help you today?
|
Mohd A. |
Hello Sir
|
Mohd A. |
Actually I have a recyclerview having cards of multiple layouts and I need to call differect Rest api on every cards. What approach should I use?
|
Mark M. |
the cards should not be calling a REST API -- they should be showing the results from something else calling a REST API
|
Mark M. |
we aim for "separation of concerns", trying to keep the UI logic as simple as possible, moving non-UI logic (such as REST API calls) elsewhere
|
Mohd A. |
Yeah the response that will get from REST apis need to be shown in cards view.
|
Apr 16 | 8:35 AM |
Mohd A. |
But I am asking how to manage those multiple requests.
|
Mark M. |
are you using the Google layered architecture approach? IOW, are you using ViewModel, and having it talk to repository objects that are responsible for the network I/O?
|
Mark M. |
if not, what code is making the REST API calls?
|
Mohd A. |
Yeah I am using ViewModel that would talk to repository. But I am confused should I use come kind of for loop to execute those calls?
|
Mark M. |
probably not, though it would depend a bit on the calls
|
Mark M. |
if you have N different REST calls for these cards, do you have N different functions on the repository to make those calls?
|
Mohd A. |
Yeah all calls point to different endpoints and having different request fields.
|
Mark M. |
in that case, a loop probably will not help
|
Mark M. |
your viewmodel will just need to make those N calls, probably in N separate lines of code
|
Mark M. |
the viewmodel can then make those results available to your activity/fragment
|
Apr 16 | 8:40 AM |
Mark M. |
that could be through N separate LiveData objects, or a single LiveData object representing the result of all N calls combined
|
Mohd A. |
What good approach will be suitable to run those APIs in parallel or at same time.
|
Mohd A. |
?
|
Mark M. |
that will depend a bit on how you have set up the repository API
|
Mark M. |
if you are using RxJava or Kotlin coroutines, there are recipes for making that work a bit more parallel
|
Mark M. |
if your repository is using callbacks and doing its own thread stuff, then the repository would be responsible for parallelism (e.g., using a thread pool)
|
Mohd A. |
I am using coroutines but not able to figure it out to run in parallel.
|
Mark M. |
does your repository API use suspend functions? if so, you can use async/await to do the work in parallel
|
Mohd A. |
Yeah it is using suspend function.
|
Mark M. |
https://klassbook.commonsware.com/lessons/Corou... shows a single async builder, with await() to find out the results
|
Mark M. |
there is also awaitAll(): https://kotlin.github.io/kotlinx.coroutines/kot...
|
Mohd A. |
Thanks for the your quick help.
|
Apr 16 | 8:45 AM |
Mohd A. |
Will try to use this.
|
Mark M. |
if the work is being done on a multi-threaded dispatcher, such as Dispatchers.IO, then the calls may be done in parallel
|
Mohd A. |
Sir, I am not good in threading stuff. Would you please suggest something to become expertise in threading.
|
Mark M. |
very few people are "good in threading stuff" :-)
|
Mohd A. |
Yeah right.
|
Mark M. |
coroutines is a good choice for how to deal with concurrency and parallelism
|
Mohd A. |
Okay..For that I am currently reading your written coroutine book.
|
Mark M. |
and I apologize for not updating that recently -- my time has been taken up by other books
|
Mark M. |
if you want lower-level knowledge, you could look at books on Java concurrency
|
Mark M. |
the best book on that was "Java Concurrency in Practice", though it's getting a bit old, and I do not know if there is something newer that is similar
|
Apr 16 | 8:50 AM |
Kai H. | has entered the room |
Kai H. |
hi
|
Mohd A. |
No, there is no any update for this book from very long time.
|
Mark M. |
Mohd: I hope to update it again in a couple of months
|
Mark M. |
Mohd: let me take a question from Kai, and I will come back to you in a bit
|
Mark M. |
Kai: hi! how can I help you today?
|
Kai H. |
I try to add multiple Views with a custom layout to a LinearLayout
|
Kai H. |
(programmatically)
|
Kai H. |
The custom layout has a TextView. When I try to set the Text of the View, I always update the TextView of the first Element, not the one just added
|
Mark M. |
you would need to hold onto all of those multiple views
|
Mark M. |
or, hold onto the dynamically-generated IDs that you assign them
|
Mark M. |
or, switch from your LinearLayout approach to RecyclerView
|
Mohd A. | has left the room |
Kai H. |
I guess the problem is that I have a fixed id?
|
Apr 16 | 8:55 AM |
Mark M. |
if you add N copies of a custom view to a LinearLayout, and you call findViewById() on the LinearLayout for an ID of a widget inside a custom view, you will get any of the N copies of that widget
|
Kai H. |
TextView listItemText = listItem.findViewById(R.id.userListItemText);
|
Mark M. |
is listItem the LinearLayout or the custom view?
|
Kai H. |
The custom view
|
Mark M. |
then listItem itself must be the first custom view
|
Mark M. |
if you are getting the TextView from the first custom view
|
Kai H. |
View listItem = View.inflate(getContext(), R.layout.listItem, linearLayout);
|
Mark M. |
is TextView listItemText = listItem.findViewById(R.id.userListItemText); on the next line in your source?
|
Kai H. |
I guess I always get the same listitem here and re-add it to the layout all the time?
|
Kai H. |
Yes
|
Mark M. |
I have not used View.inflate(), but my guess is that it is just using LayoutInflater's own inflate()
|
Mark M. |
if so, View.inflate() should be creating a new custom view each time
|
Mark M. |
and I cannot explain why findViewById(), on that custom view, would return a widget from outside of that custom view
|
Kai H. |
I cannot explain it either :D
|
Apr 16 | 9:00 AM |
Kai H. |
Why only the TextView of my first custom LinearLayout view gets updated, not the one I am adding.
|
Mark M. |
if you had TextView listItemText = linearLayout.findViewById(R.id.userListItemText); I could see behavior like that
|
Mark M. |
you originally wrote "I try to add multiple Views with a custom layout to a LinearLayout" -- are you calling View.inflate() and stuff in a loop?
|
Kai H. |
Yes, I am
|
Kai H. |
The goal is to have a simple "list" without using RecyclerView or any other List, to circumvent issues with scrolling
|
Mark M. |
your LinearLayout will still need to be in a ScrollView/NestedScrollView, otherwise it might not fit on the screen
|
Kai H. |
It is, that is the reason for the circumvention :D
|
Mark M. |
so I am not certain what "circumvent issues with scrolling" means and how the LinearLayout approach will help there
|
Mark M. |
¯\_(ツ)_/¯
|
Kai H. |
If I make it a List, then I don't know how to display all the entries. And there might be confusion on what to scroll
|
Mark M. |
I'll take your word for it
|
Apr 16 | 9:05 AM |
Kai H. |
But I might end up doing it with RecyclerView eventually. It's a proof of concept right now and supposed to be held simple
|
Mark M. |
in your loop, you might try breakpoints or Log statements to confirm the object IDs of listItem and listItemText, to see what you get
|
Mark M. |
and you might try Layout Inspector to confirm that your LinearLayout is getting set up the way that you expect
|
Kai H. |
They are always the same
|
Mark M. |
View.inflate() is returning the same object each time?
|
Mark M. |
if so, stop using View.inflate() :-)
|
Kai H. |
Yes, it seems like it.
|
Mark M. |
try switching to LayoutInflater directly
|
Mark M. |
(preferably getting the LayoutInflater by calling getLayoutInflater() on your activity)
|
Mark M. |
and see if that helps
|
Apr 16 | 9:10 AM |
Kai H. |
It actually doesn't. Huh. I still get the same views each time
|
Mark M. |
are you using the two-parameter inflate() (i.e., inflate(R.layout.listItem, linearLayout);)
|
Kai H. |
Yes
|
Mark M. |
if so, try inflate(R.layout.listItem, linearLayout, false); and manually add the inflated item to the LinearLayout
|
Mark M. |
(with an appropriate LinearLayout.LayoutParams)
|
Kai H. |
Aaaand it works
|
Kai H. |
(Without having added a LayoutParams)
|
Mark M. |
LinearLayout might have a default LayoutParams that it uses
|
Mark M. |
it has been years and years since I last used two-parameter inflate() methods, so I forget the rules
|
Apr 16 | 9:15 AM |
Mark M. |
I would not have expected the behavior that you were seeing, though
|
Kai H. |
Neither would I.
|
Mark M. |
but, at least now you have a path for moving forward
|
Kai H. |
Thank you
|
Kai H. |
I noticed I am confused by layouts ;-)
|
Kai H. |
Should inflating the same layout twice give you two different objects?
|
Mark M. |
with the three-parameter inflate(), yes
|
Mark M. |
with the two-parameter inflate(), apparently not
|
Kai H. |
Shouldn't it be intended behaviour that if you inflate a Button at different places you always get the same button?
|
Kai H. |
If so, how can you have different objects with the same layout?
|
Kai H. |
So many questions ;-)
|
Mark M. |
ah, I see the problem
|
Mark M. |
the two-parameter inflate() is not returning the inflated layout -- it returns the object you passed in as the root
|
Kai H. |
I see
|
Mark M. |
so, inflate() was returning your LinearLayout
|
Mark M. |
and your findViewById() call was being made on the LinearLayout
|
Apr 16 | 9:20 AM |
Mark M. |
API Level 1 methods can be weird sometimes :-)
|
Kai H. |
I now have my list
|
Kai H. |
Should one not use them anymore?
|
Mark M. |
if you mean methods that were introduced in API Level 1, they are unavoidable
|
Mark M. |
lots of what we use was introduced back in Android 1.0
|
Mark M. |
it's more that we have gotten better at API design as an industry in the intervening decade-plus
|
Kai H. |
And now we are stuck with the old APIs?
|
Mark M. |
they can't change them in ways that break backwards compatibility
|
Mark M. |
so, the two-parameter inflate() will have a funky return value for the rest of time
|
sudokai | has entered the room |
Mark M. |
now, in some cases, the old APIs get deprecated and replaced
|
Mark M. |
at which point we try to avoid the deprecated ones
|
Apr 16 | 9:25 AM |
Mark M. |
let me take a question from sudokai, and if there is time, I'll swing back to you
|
Mark M. |
sudokai: hi! how can I help you today?
|
Mark M. |
(in the remaining 5 minutes of the chat)
|
sudokai |
Hi, what are the different foreground service notification types for?
|
Mark M. |
you mean on Android 10+?
|
sudokai |
Yes
|
sudokai |
FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
sudokai |
FOREGROUND_SERVICE_TYPE_NONE
|
sudokai |
Why should I use one?
|
Mark M. |
if so, they are kind of a quasi-permission system, in that you have to declare the foreground service type to be able to use that capability
|
sudokai |
But take workmanager for example
|
sudokai | |
sudokai |
Do you need to specify the type when creating the foreground info?
|
sudokai |
The example listed there does not
|
Mark M. |
probably not, though technically it would depend on what the work does
|
sudokai |
I'm using WorkManager to upload stuff
|
Mark M. |
View paste
|
Mark M. |
now, I don't know what "dataSync" controls
|
sudokai |
Okay
|
Mark M. |
but, for example, if you want to use the media projection APIs to take screenshots or record screencasts, you would need to add mediaProjection as a foreground service type
|
sudokai |
Thanks
|
sudokai |
I'll read a bit more
|
sudokai |
Back to you Kai
|
Mark M. |
note that they added camera and something else in Android R -- I forget the second oen
|
Mark M. |
er, one
|
sudokai |
;)
|
Mark M. |
OK, two-minute free-for-all: any last questions?
|
Kai H. |
;-)
|
Apr 16 | 9:30 AM |
Kai H. |
I think time is up
|
Mark M. |
yeah, that's a wrap for today's chat
|
Mark M. |
the transcript will go up on https://commonsware.com/office-hours/ shortly
|
sudokai |
No more questions from me
|
sudokai |
Thanks
|
Mark M. |
the next chat is Saturday at 4pm US Eastern
|
Mark M. |
have a pleasant day, and stay healthy!
|
Kai H. |
Same
|
Kai H. | has left the room |
sudokai | has left the room |
Mark M. | turned off guest access |