Dec 29 | 8:20 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Dec 29 | 8:25 AM |
Kai H. | has entered the room |
Mark M. |
hello, Kai!
|
Kai H. |
Hello Mark
|
Mark M. |
how can I help you today?
|
Kai H. |
By lending me your knowledge and experience
|
Kai H. |
I have a small apps that has several chapter, each chapter with several topics. How would you model that?
|
Dec 29 | 8:30 AM |
Kai H. |
several chapters
|
Mark M. |
I guess I'm confused -- do you mean that this app is an ebook reader?
|
Kai H. |
I gave too little information :D
|
Kai H. |
It's pretty much a representation of javapractices.com
|
Kai H. |
So a chapter has a title and several topics, and a topic has a title and some content.
|
Mark M. |
is "some content" represented by data (e.g., HTML) or is "some content" a bit of custom code that is in the app?
|
Kai H. |
Some content is html/text
|
Mark M. |
OK, that sounds like an ebook reader :-)
|
Mark M. |
for example, *The Busy Coder's Guide to Android Development*, back when I maintained it, was distributed as an APK, as a custom ebook reader wrapped around the book content
|
Dec 29 | 8:35 AM |
Mark M. |
(in addition to being distributed in PDF/EPUB/Kindle formats)
|
Mark M. |
specifically, my APK was an EPUB reader, so I used existing EPUB libraries to extract the chapters for display
|
Kai H. |
So you would suggest the same for me?
|
Mark M. |
well, in my case, that was an easy way to represent the content, since I was creating EPUB for direct distribution
|
Mark M. |
you might just set up a directory tree in assets/ with your HTML, plus some JSON to serve as a "table of contents"
|
Mark M. |
later, in addition to the EPUB, I packaged a database that contained a full-text indexed copy of the prose, for use in searching
|
Kai H. |
OK
|
Mark M. |
if you wanted the full-text index, you might consider just going with SQLite for the book content entirely
|
Dec 29 | 8:40 AM |
Kai H. |
So you didn't model it as data classes or something?
|
Dec 29 | 8:40 AM |
Mark M. |
well, this pre-dated Kotlin ;-)
|
Kai H. |
I have that planned, to back it up with a database. Right now it's all scraped from the website in question.
|
Kai H. |
So I don't control the content so far, which limits my options a little. Or rather I need to process it first.
|
Mark M. |
if by "model it as data classes", you mean have individual classes per chapter or topic, definitely not
|
Mark M. |
the only way I would do that is if I had custom UI that I needed on a per-chapter/topic basis, such as for demos
|
Mark M. |
which is why I asked the question that I did back at the top
|
Kai H. |
I meant something like "data class Chapter(val name: String, var topics: List<Topic>)!"
|
Mark M. |
ah, yes, that I had
|
Kai H. |
I guess I'll have a Fragment for Chapters and one for Topics.
|
Mark M. |
that will depend a bit on your planned UI, but it's certainly not out of the question
|
Mark M. |
Chapter and Topic would be be model objects, and ChapterFragment and TopicFragment would be renderers of those model objects
|
Kai H. |
Exactly. At the same time, I wonder if using a data class for Chapter and Topic is worth it for an app of this size.
|
Kai H. |
Which is partly why this question came up.
|
Mark M. |
as opposed to... what?
|
Kai H. |
Also I am not really satisfied with Chapter referencing Topic when the Topic might not be known yet.
|
Dec 29 | 8:45 AM |
Kai H. |
List<String> :D
|
Mark M. |
"might not be known yet"?
|
Kai H. |
And a Map<String, List<String>> I guess.
|
Kai H. |
As I parse the content at the moment, I get all the chapters first, then when a chapter is clicked it get the respective topics.
|
Mark M. |
ah, is your plan to scrape the Web site in real time?
|
Kai H. |
It is for now. Later I wanna scrape it once, then use the content via a database and keep it current by scraping in the background.
|
Mark M. |
does the site actually change? copyright is 2018, and the content seems... older
|
Kai H. |
I actually don't know. There are these "new" pictures on some topics ;-)
|
Kai H. |
So I just assumed and thought that if I implement the scraping logic, I can use it later anyway.
|
Kai H. |
But I might end up not doing so.
|
Mark M. |
agreed, though scraping is always a dicey proposition -- one design change in the Web page and your scraper needs a rewrite
|
Kai H. |
Yes, it is.
|
Kai H. |
And I have seen more structured web pages. I have already spent quite some time in trying to scrape it.
|
Mark M. |
I assumed (incorrectly!) that you were going to scrape offline and package the updates with the app, rather than try realtime scraping
|
Mark M. |
the advantage of only scraping offline is that when the scraper breaks, it doesn't affect your users
|
Mark M. |
(by "offline" here, I mean scraping from your development machine or some server, not in the app itself)
|
Dec 29 | 8:50 AM |
Kai H. |
Yes. That is a step that will come in the future.
|
Mark M. |
but if the content does not change frequently, scraping in-app seems unnecessary
|
Kai H. |
Sure
|
Kai H. |
It takes a lot of time anyway, so I might just do without.
|
Mark M. |
then, the app itself is just a presentation of the material; you can use other tools in other languages for the scraping and packaging of that material
|
Kai H. |
Yes, I could :D
|
Mark M. |
BTW, that site's RSS feed suggests that it has not been updated since September 2018
|
Mark M. |
admittedly, that RSS feed is rather truncated, so I don't know how much to trust it
|
Mark M. |
oh, wait, there's a Last Updated date in the footer that also points to September 2018
|
Mark M. |
(and if the In Memoriam is for the person who created the site... it might never be updated again)
|
Dec 29 | 8:55 AM |
Kai H. |
I assumed it was for another person
|
Mark M. |
it certainly could be
|
Mark M. |
FWIW, https://web.archive.org/web/changes/http://www.... also suggests that the site has not changed since September 2018
|
Kai H. |
I guess if I scraped before hand and got everything from a database, then having data classes is pretty much a must or makes things easier, at least (if I use room for example).
|
Kai H. |
You made your point ;-)
|
Mark M. |
most likely, you will want model classes (as data class or otherwise) that match your data storage and how you will read it in
|
Mark M. |
another advantage of parsing this off-app and just packaging the content is that it minimizes the number of write operations that you need to worry about -- it's down to things like history or bookmarks, none of which is absolutely essential
|
Dec 29 | 9:00 AM |
Kai H. |
I don't get the second part of your last sentence.
|
Kai H. |
Oh, now I did :D
|
Mark M. |
the primary content presumably is read-only
|
Kai H. |
Yes.
|
Mark M. |
any data beyond that which you wish to collect (visited-topic history, search history, bookmarks, etc.) is up to you
|
Mark M. |
and you can choose how much of that to do and when to tackle it
|
Mark M. |
plus, how you store that user-mutable data does not necessarily have to be the same as how you store the read-only data
|
Kai H. |
I think my follow-up question is also answered. I was wondering if I have one or many ViewModels for the topics, as those change according to the chapter that is selected.
|
Mark M. |
that will largely be dictated by your UI
|
Kai H. |
But I guess there will be one ViewModel, with the topics changed if the chapter is changed (or rather when another topic Fragment is displayed).
|
Mark M. |
from a class standpoint, my guess is that there will be at most one ViewModel class per fragment class
|
Mark M. |
from an instance standpoint, it will depend a bit on how you use those fragments and whether multiple of them will be around at once (e.g., some sort of tabbed presentation)
|
Dec 29 | 9:05 AM |
Kai H. |
How would I implement multiple ViewModels for multiple sets of topics?
|
Kai H. |
Without doing it hard coded.
|
Mark M. |
what do you mean by "multiple sets of topics"?
|
Kai H. |
Let's say there is a tabbed view of chapters. Each chapter would have its topics and a ViewModel.
|
Kai H. |
So if there are 5 Chapters, there would be 5 VMs holding the Topics for each.
|
Mark M. |
if by "5 VMs" you mean "5 VM instances" then yes
|
Mark M. |
if by "5 VMs" you mean "5 VM classes" then no
|
Kai H. |
I mean the first
|
Mark M. |
right, so each ChapterFragment has a ChapterViewModel
|
Mark M. |
perhaps pulling from a ContentRepository or BookRepository or something along those lines
|
Kai H. |
Yes
|
Kai H. |
(I already have ChapterViewModel, but right now that holds the list of chapters)
|
Mark M. |
you may find that you do not need a TopicFragment -- particularly if you are doing tabs per chapter, there is only so much screen space, and so you might not have more than one topic visible at a time
|
Dec 29 | 9:10 AM |
Mark M. |
but, if you do elect to have a TopicFragment, it's possible that it has a TopicViewModel to match
|
Kai H. |
So how would a ViewModel holding the topics for Chapter "A" be distinguished from one holding for Chapter "B"?
|
Mark M. |
um, identifiers of some form
|
Mark M. |
each chapter has an ID
|
Kai H. |
:D
|
Mark M. |
each topic has an ID
|
Mark M. |
a TopicViewModel knows the ID of the topic that its fragment is responsible for displaying
|
Mark M. |
depending on the data model, a TopicViewModel might also need to know the chapter ID
|
Mark M. |
(particularly if topic IDs are not unique across your whole space, so the unique identifier of a topic is a chapter ID + a locally-unique topic ID)
|
Kai H. |
Or the ChapterViewModels the topic IDs.
|
Mark M. |
ummm... I think that sentence is missing a verb
|
Kai H. |
Would you go with a chapter knowing its topics or a topic knowing its chapters?
|
Mark M. |
is a topic contained by more than one chapter?
|
Kai H. |
=> depending on the data model, a TopicViewModel might also need to know the chapter ID. Or the ChapterViewModels the topic IDs.
|
Kai H. |
I don't think so.
|
Mark M. |
then this feels like a 1:N relation between chapter and topic
|
Kai H. |
I assume as much
|
Mark M. |
from a relational database standpoint, a topic knows its containing chapter, as a foreign key
|
Mark M. |
from an in-memory standpoint, it may not matter -- it all depends on what sort of API your repository exposes
|
Mark M. |
in the end, given an identifier of some form, TopicViewModel needs to get to the content to display
|
Dec 29 | 9:15 AM |
Mark M. |
how you accomplish that is going to be dictated a lot by your data storage approach and the repository implementation that wraps around it
|
Mark M. |
(plus caching considerations, etc.)
|
Kai H. |
I plan to try and follow "Exploring Android" for all that :D
|
Mark M. |
one key limitation of *Exploring Android* is that it has a fairly simplistic data model: a to-do item
|
Mark M. |
there is no notion of, say, categories of to-do items
|
Kai H. |
Which is why I have those questions :D
|
Kai H. |
Or rather why I asked them here.
|
Kai H. |
But I guess scraping first, then using the scraped data will be my way forward.
|
Kai H. |
Should make some things quite a bit easier.
|
Kai H. |
And for the rest there will be other office hours ;-)
|
Mark M. |
yeah, once you figure out how you want to collect and store the content, other aspects of the app may become more obvious, in terms of how you want to approach them
|
Dec 29 | 9:20 AM |
Kai H. |
And I guess it's just trial and error and what works best for me on the way.
|
Mark M. |
we always hope for short trials and few errors
|
Mark M. |
somehow, it does not always work out that way
|
Kai H. |
Lucky is the one who has someone else to help him try less long and err less.
|
Kai H. |
My last question would have been "how to learn writing idiomatic Android Kotlin", but I guess it's also trial and error and searching stack overflow ;-)
|
Dec 29 | 9:25 AM |
Mark M. |
well, to an extent, we are still figuring that out
|
Mark M. |
and the definition of "idiomatic" is also tied to the environment -- Jetpack Compose has its own concept of "idiomatic" that will look somewhat foreign to developers use to the classic View system
|
Mark M. |
(er, "used to the classic View system")
|
Dec 29 | 9:30 AM |
Mark M. |
and that's a wrap for today's chat
|
Mark M. |
the next one is *tomorrow* at 7:30pm US Eastern
|
Mark M. |
have a pleasant day!
|
Kai H. | has left the room |
Mark M. | turned off guest access |