Jun 8 | 8:50 AM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Jun 8 | 9:00 AM |
Dimitris K. | has entered the room |
Dimitris K. |
Hey Mark how's life?
|
Mark M. |
hello, Dimitris!
|
Mark M. |
how can I help you today?
|
Dimitris K. |
So today I have two major questions
|
Dimitris K. |
First one will be regarding an updater app I'm making
|
Mark M. |
go right ahead
|
Jun 8 | 9:05 AM |
Dimitris K. |
So it has a download manager, what I currently have is a class extending async task that takes a set or params and downloads the according files
|
Dimitris K. |
I was wandering if using the download manager would make more sense (the whole downloading part is going to be done in a service)
|
Mark M. |
OK, first, there is no point in using AsyncTask in a service
|
Mark M. |
the point behind AsyncTask is to do something on the main application thread after the background work
|
Mark M. |
and there are very few scenarios in which you want a service doing anything on the main application thread
|
Dimitris K. |
Since it doesn't need to use the main thread right ?
|
Mark M. |
right
|
Mark M. |
either use a Thread, or a ThreadPoolExecutor
|
Mark M. |
in terms of using DownloadManager... there are pros and cons
|
Dimitris K. |
What would be a proper design patern for each case
|
Dimitris K. |
Just so you get the point
|
Dimitris K. |
The files are going to be XML configuration files and media files
|
Mark M. |
um, whatever you are doing with AsyncTask, replace with the thread or thread pool
|
Dimitris K. |
They will be stored and parsed only after everything is downloaded and hash checked for being valid
|
Mark M. |
for example, if you only want to download one at a time, just use an IntentService
|
Mark M. |
as it gives you a background thread "for free"
|
Mark M. |
if you want to parallelize the downloads, use a ThreadPoolExecutor, typically sized at 2N+1 threads, with N being the # of cores
|
Dimitris K. |
I want to make edge case scenarios handled as easily as possible
|
Dimitris K. |
I don't really care about parallel downloads
|
Mark M. |
execute Runnables and whatnot on the ThreadPoolExecutor, with some sort of logic to know when they are all done, so you can do your post-download processing
|
Jun 8 | 9:10 AM |
Mark M. |
then an IntentService is the simplest solution
|
Mark M. |
you will want to make it be a foreground service, though, particularly with an eye towards Android O, in case your downloads and post-processing will take over a minute
|
Dimitris K. |
I need safe downloads this process is going to be done for a "player" app update purpose
|
Mark M. |
what does "safe" mean in this context?
|
Dimitris K. |
I am supporting fixed devices only
|
Dimitris K. |
Digital signage ;)
|
Dimitris K. |
Huge custom rooted screens supporting 5.1
|
Mark M. |
the downside of DownloadManager is that it cannot download to your app's internal storage
|
Mark M. |
it can only download to external storage
|
Dimitris K. |
I need to have a tracking mechanism that makes sure that everything I need to download is downloaded properly
|
Mark M. |
and you cannot use certificate pinning or anything to further secure the connection
|
Dimitris K. |
I actually need it on an external storage
|
Dimitris K. |
Since the data will be parsed by a second app
|
Dimitris K. |
Hmm that's an issue
|
Mark M. |
that does not imply that you need external storage
|
Mark M. |
that only means that the second app has to be able to get to the data
|
Dimitris K. |
So download manager ain't working with certificate pinning
|
Mark M. |
correct
|
Dimitris K. |
:/
|
Mark M. |
you have no way of teaching it the rules
|
Dimitris K. |
Httpurlconnection it is then
|
Mark M. |
and even with network security configuration on Android 7.0, that only affects your process, and DownloadManager is a separate app
|
Mark M. |
I would recommend OkHttp over HttpURLConnection, but that's just me
|
Dimitris K. |
Regarding the Android priority job queue open source library
|
Jun 8 | 9:15 AM |
Mark M. |
do you mean https://github.com/yigit/android-priority-jobqueue ?
|
Dimitris K. |
Could it help me out ? Since I should also have a job scheduler implemented
|
Dimitris K. |
Yes that one
|
Mark M. |
I have not used it
|
Mark M. |
so I do not know how its integration with JobScheduler works
|
Dimitris K. |
My updates have to be either triggered or follow a set of rules
|
Mark M. |
I do not know what you are looking for a library to solve with respect to that
|
Mark M. |
if your objective is to support JobScheduler but also support older devices, perhaps that library can help, or use https://github.com/evernote/android-job
|
Dimitris K. |
Thankfully I'm only supposed to support 5.1
|
Dimitris K. |
Regarding the edge case handling (wifi connection lost, device rebooted) is there any suggested patern to use for my download manager
|
Jun 8 | 9:20 AM |
Mark M. |
for loss of connectivity, scheduling a job to give you control again after you get a connection is a fine solution
|
Mark M. |
in that case, you might dispense with the IntentService and just do everything in a JobService, with your own forked background thread (as unfortunately you're responsible for that yourself with JobScheduler)
|
Mark M. |
and if you think Yigit's library will help with that, give it a try
|
Mark M. |
regarding a reboot, there would seem to be two corner cases:
|
Mark M. |
1. what happens if the device reboots while you are in the middle of processing a job?
|
Mark M. |
2. what happens if the device reboots while you are waiting on connectivity?
|
Mark M. |
if you use a persistent job with JobScheduler and your JobService, #2 should be handled for you automatically
|
Mark M. |
I have never tried #1 and so I do not know what happens if the device reboots while a job is in progress but has not been signalled as being completed
|
Mark M. |
you would have to run some tests to see if JobScheduler handles that
|
Mark M. |
it should, but there are lots of things in Android that I think "it should" do, but it doesn't :-(
|
Dimitris K. |
Can I fetch a jobScheduler status
|
Mark M. |
you can get a list of the scheduled jobs, if that is what you mean
|
Mark M. | |
Dimitris K. |
My service is going to run on device boot so maybe I should just check the jobs list
|
Jun 8 | 9:25 AM |
Mark M. |
you would have to run some tests to see if the jobs are ready at the point of an ACTION_BOOT_COMPLETED receiver being invoked
|
Mark M. |
in principle, they should be
|
Dimitris K. |
The devices will be public displays so I need to have a solid control
|
Mark M. |
but, stranger things have happened
|
Dimitris K. |
Yeah a lot of testing will be needed :/
|
Dimitris K. |
Do you have any experience with silent apk updates ?
|
Mark M. |
I have not worked in rooted environments in general
|
Dimitris K. |
It's a dark place since the client requirements surpase what the os was made for
|
Mark M. |
in the long term, Android Things is likely to be the better platform for this sort of device, IMHO
|
Dimitris K. |
Just to finalize question 1. I should go for the service - own thread - urlhttpconnection or okhttp solution right ?
|
Mark M. |
compared with DownloadManager, yes
|
Dimitris K. |
Awesome this is a really important decision I needed to make and you really helped me :D
|
Mark M. |
I am happy to be useful!
|
Dimitris K. |
So question 2. ?
|
Jun 8 | 9:30 AM |
Dimitris K. |
In my awesome strange setup the updater tool gets data saves it inside an accessible folder
|
Dimitris K. |
In the data an apk of the "player" app exists
|
Dimitris K. |
It gets installed "somehow" and runs
|
Dimitris K. |
Now that player app
|
Dimitris K. |
Is going to build it's ui by parsing xml configuration files
|
Dimitris K. |
So imagine that the configuration my tell me that the 1st screen consists of 2 sub screens devided horizontally
|
Dimitris K. |
The upper part should have a slider with images and videos for example
|
Dimitris K. |
The question is what kind of generic structure should I use for the sub screens
|
Dimitris K. |
Should they be fragments or views or custom components
|
Jun 8 | 9:35 AM |
Mark M. |
I am not certain what "custom components" would be other than fragments and views
|
Mark M. |
most of your application logic should reside in some sort of controller/presenter thing, typically
|
Dimitris K. |
Ok right it could maybe be custom viewgroups
|
Mark M. |
digital signage does not involve user input usually -- am I correct in assuming that your UI is output-only?
|
Dimitris K. |
The UI is going to be interactive
|
Dimitris K. |
So I will have buttons and so
|
Dimitris K. |
The goal is to make as much abstraction as possible regarding sizes and positions
|
Mark M. |
but the device screen is physically fixed, and the user can't mess with settings, so there should be no configuration changes... right?
|
Dimitris K. |
So if the client needs a slider that takes 20% of the screen height or 30% I should be able to support it if he wants it to take 20% horizontally that should also be supported
|
Mark M. |
that sounds like you want to create a LayoutInflater equivalent
|
Dimitris K. |
Yes they can navigate through fixed paths
|
Mark M. |
unfortunately, LayoutInflater itself can only be used with resources
|
Mark M. |
I seem to recall libraries out on the Android Arsenal that offered LayoutInflater-style inflation-from-data-file capabilities
|
Jun 8 | 9:40 AM |
Dimitris K. |
Hmm that would be nice ! But what about something built by me
|
Mark M. |
I would approach the problem in much the same fashion, with a dedicated set of classes for "inflating" the UI from the configuration files
|
Dimitris K. |
The subscreens are going to always have specific set of possibilities
|
Mark M. |
that can simplify the inflation logic somewhat
|
Dimitris K. |
Should I have a view base implementation or fragment
|
Mark M. |
um, to some extent, neither
|
Dimitris K. |
So single activity and adding removing views or fragments
|
Dimitris K. |
:/
|
Mark M. |
the "inflater" would assemble a view hierarchy based on the configuration file
|
Mark M. |
if you have individual discrete views that are fairly distinctive, having those be custom views is reasonable
|
Mark M. |
but then the "inflater" would hand over the view hierarchy over to your controller/presenter thingy
|
Dimitris K. |
For example a slideshow
|
Mark M. |
whether a "slideshow" is necessarily a custom view, I can't say
|
Dimitris K. |
I guess I should be able to have a custom slideshow that can work on different sizes
|
Mark M. |
I wouldn't rule it out, and you probably want to have some sort of packaged "slideshow" component
|
Dimitris K. |
Yes
|
Mark M. |
but whether it is truly a custom view (i.e., subclass of ViewGroup) or more of a local controller/presenter around something else (e.g., RecyclerView) is up to you
|
Mark M. |
I would tend towards the latter approach
|
Dimitris K. |
I need it to be something like small apps in my app
|
Jun 8 | 9:45 AM |
Mark M. |
ok, then the "small apps" themselves are their own MVP/MVC/MVVM units
|
Dimitris K. |
Yes that would be perfect I guess
|
Mark M. |
the "inflater" is stitching together those small apps
|
Dimitris K. |
Would it make sense to have them as modules ?
|
Dimitris K. |
Yep I really like that approach
|
Mark M. |
if you want separate teams working on them, or you want to reuse them across projects, yes
|
Mark M. |
otherwise, while they might be separate Java packages, I'm not sure that having them as separate Android Studio modules would gain you much value
|
Dimitris K. |
What about keeping the project readable and clean
|
Dimitris K. |
Packages should be enough right ?
|
Mark M. |
if you find having N modules to be more readable and clean than one larger module, feel free to use multiple modules
|
Mark M. |
typically, though resources are not affected by that
|
Dimitris K. |
Any attempt to dynamically update and apps module without a new app update ?
|
Mark M. |
that is difficult with resources
|
Mark M. |
it also presents security issues, but your whole environment is one big security issue with a screen attached
|
Dimitris K. |
I know some apps do it and I know it's not legal in play store apps but since I don't use the play store it would be interested
|
Dimitris K. |
^^ indeed
|
Mark M. |
I have a chapter on dynamic code loading in the book
|
Dimitris K. |
Awesome I'll read that
|
Jun 8 | 9:50 AM |
Dimitris K. |
Any idea of how the inflater class can be structured ?
|
Dimitris K. |
Should I just take a look at the inflater source code
|
Mark M. |
the LayoutInflater code is fairly nasty, last I looked at it
|
Mark M. |
and you have a more controlled scenario, whereas LayoutInflater needs to deal with custom attributes and such
|
Dimitris K. |
(the only reason I'm not too scared for the security issues is that the data is always public data so if my login credentials are not leaked it should be fine )
|
Mark M. | |
Dimitris K. |
I hash check everything before showing it
|
Dimitris K. |
Maybe I should just encrypt my hash containing table
|
Mark M. |
I would use digital signatures
|
Mark M. |
hash checks are good for confirming that the download wasn't scrambled
|
Mark M. |
but if they can hack what you are downloading, they can hack your list of hash values
|
Mark M. |
so that their modified download has a valid hash value
|
Dimitris K. |
True :/
|
Jun 8 | 9:55 AM |
Mark M. |
whereas to hack the digital signature, they would need access to the developer machine, not the digital sign
|
Dimitris K. |
I guess the hardest task is making the inflater class right ?
|
Mark M. |
well, given your "small apps" model, the inflater would appear to have two roles:
|
Mark M. |
1. configuring the overarching layout (e.g., the splits of screen space to be allocated to the small apps)
|
Mark M. |
2. handing configuration data over to the "small apps"
|
Mark M. |
it may be that each small app knows how to "inflate" itself, given its subset of the configuration data
|
Mark M. |
and so the top-level inflater is handling the screen space allocation and instantiating each "small app"
|
Dimitris K. |
The main container is my activity right ?
|
Mark M. |
presumably
|
Jun 8 | 10:00 AM |
Dimitris K. |
And I guess maybe it would nice to have a definite ed order of inflation
|
Dimitris K. |
Top to bottom or so
|
Mark M. |
I do not know how flexible your inflater needs to be
|
Dimitris K. |
Worst case scenario it should decide the screen into 4 rectangles of different sizes
|
Dimitris K. |
Devide*
|
Dimitris K. |
(at least it's always rectangles :D )
|
Mark M. |
ideally, you boil that down into a fairly simple algorithm
|
Mark M. |
e.g., the primary split is horizontal or vertical, with X% being the dividing point
|
Mark M. |
and then within the first split we have an optional second-tier split
|
Mark M. |
and so on
|
Mark M. |
...and that's a wrap for today's chat
|
Dimitris K. |
That's a nice point thanks !
|
Mark M. |
the transcript will be posted to https://commonsware.com/office-hours/ shortly
|
Dimitris K. |
As always I'm very thankful
|
Mark M. |
the next chat is Tuesday, also at 9am US Eastern
|
Mark M. |
you are very welcome!
|
Mark M. |
have a pleasant day!
|
Dimitris K. |
Enjoy the rest of the day :D
|
Dimitris K. | has left the room |
Mark M. | turned off guest access |