Android, Linux, FLOSS etc.

My code

Subscribe to a syndicated RSS feed of my blog.


Sun, 03 Jul 2016


In my Wallpapers app for Android, I have a popular tab, to show the most popular wallpapers people are using. I generate it by going through my Apache web server log files, and pulling all downloaded wallpapers. I see which downloads are equal to or greater than the file size (i.e. not aborted before download). I also only count a download of a wallpaper from a particular IP only once. I also see the date of the download.

The date the wallpapers became available on the app varies. Some were available on the day the app launched. On the other hand, I just added several a few hours ago, so those have only available for a few hours.

This creates a problem when calculating for popularity. If I count popularity by all downloads, the older wallpapers will keep showing up on top, since they have the history there. Getting on top of the popular page increases the downloads of a wallpaper, so it becomes self-perpetuating too. On the other hand, if I count only downloads from the past day or two, there could be a statistical fluke where a normally popular wallpaper disappears down the list, while some usually unpopular one hits the top. It's best to count that older information in some way. But how?

I came up with a scoring scheme which I am happy with. It's based something off of the idea (but not the exact rate) in physics of weak force beta decay. I count how many days back a download was - if it was 10 days ago, then variable d is 10. Then I put it into the algorithm 1log10(d+1) . This is the score for that download. Which in this case is ≈ 0.96. Then I add all those scores up for that wallpaper and that is its popularity score.

Do you see anything wrong with this? What about wallpapers downloaded on the day this is calculated? Then d would equal 0, and log10(d+1) would equal 0, and we would try to be calculating 10, which is impossible. What I do in this case where there are same-day downloads is divide by 1.5. So we divide by (d+1.5) not (d+1) in that case.

That same-day exception is arbitrary, but all of this is arbitrary. I might futz with the algorithm more, but it has been working well so far. Old reliable popular wallpapers which stay popular show up on the top of the popular page, but so do newer wallpapers which were uploaded a few days back and have proved to be popular since then. It seems to have worked out well so far.

[/android] permanent link

Version 2

So I spent 2 1/2 months writing version 1 of an Android app. I wanted it to be a minimally viable product, as is the common parlance.

It was a minimally viable product. Actually, perhaps too minimal and perhaps not viable enough I worried. Its whole point was offering many wallpapers for Android devices, and I was worried that having only 335 wallpapers on launch was too minimal.

But that was a server-side content problem, and in the hours and days after the client launch, I added more and more wallpapers - a month later it now is 515 wallpapers, and I'm adding more every week.

So aside from the continual need to add new wallpapers, I wanted to work on features and such which I had pushed off to version 2.

At the top of the list was tabs. I was using LocalActivityManager to do tabs, which was deprecated in July 2011. I was reusing my old code which I probably wrote back in June or July 2011. It still worked though. I attempted to do something more modern in the 2 1/2 month version 1 MVP development cycle, but it was such a hassle I punted it to version 2. As it had been deprecated a long time, and I wanted something that looked good and modern and worked well, doing tabs in a modern, correct manner was top of the list for version 2 features.

I didn't expect it to take long - but it did. It took almost a month. Now, to be fair, I wasn't spending every day working exclusively on Android tabs. I was getting those 180 new wallpapers during this period. I was also doing things other than this project. Then the past few days I've been doing the other things on that list for version 2 - improving design, fixing bugs, adding features. But the bulk of the time was spent on tabs.

So if you go to the Android development training page for tabs it suggests putting a tab listener on the Action Bar, and then setting up ActionBar tabs. Unfortunately, these methods were deprecated in API 21. Unfortunately being the Android development tutorial was not updated, and is telling you to do things which are deprecated.

Also - that tutorial suggests FragmentPagerAdapter or FragmentStatePagerAdapter. FragmentPagerAdapter and FragmentStatePagerAdapter generate arcane tags for Fragments. If I want to get the tag for a fragment (after the device rotates, say) because I want to execute a method in it - I need something better. So I am using Mark Murphy's CWAC-Pager.

I also skipped the tabs on the ActionBar. I did a TabLayout with a pager though. Which needs fragments. So I rewrote the LocalActivityManager tab Activities to Fragments.

Then I wanted things to remain the same after rotation and - that was a pain. I did saveInstances in the Activity and Fragments, and check for that when rotation is done. So now it works. If the tutorial said what to do that was not deprecated, or at least said "don't try this, it's deprecated", it would have saved me time. It's done know any how.

So then I went through the list of things to do after that. With tabs done, I changed tab design and colors. I changed screen background colors, button colors, text sizes and colors etc. I put pictures of wallpapers on the categories list.

Android automated testing and user reported ANRs had shown some problems in the detail page, so I fixed those. Both were due to behavior I had not anticipated on the UI - the ImageLoader instance being killed off after long disuse was one. People clicking a detail screen, backing out and clicking another one quickly was another. My broadcastreceiver would see the old message, poll the new JSON queue and empty it. So I changed it to peek for a good JSON for the current detail wallpaper and if it didn't see anything to ignore the old broadcast, and wait for a new broadcast.

So version 2 (technically version 5 - I did three minor updates after the version 1 release) works good. It looks good - like one of the real wallpaper apps. Still some more way to go, but it's better. I did an alpha, had the automated testing check it and someone else checked it and gave me advice (thanks!) Then I did a staged rollout to 20% of users. I'll rollout to 100% soon. Then I'll continue adding new wallpapers and start working on version 3.

Although version 3 needs things done, they're lower priority than the stuff that version 1 and 2 needed. I also will be downloading some wallpapers every day. Some future features need these new wallpapers, as a wallpaper search makes more sense the more wallpapers you have.

Anyhow, with version 2 out, which is the stuff I wanted in version 1, but figured the app could launch without - now I have more time. Time to do another app. It took 3 1/2 months to get to this point, so I'm not in a rush to dive deep into something new this week. I'll take a few days (or weeks) to mess around with a few things. Measure twice, cut once - why jump into a 3.5+ month project without much thought? The stopwatch app was one I knew I could do real quick, and the wallpaper app seemed something I could do in 2-3 months, would enjoy more than alternatives, had a shot at being lucrative enough to compensate me for time spent etc. So now I'm on to the next thing, whatever that may be...

[/android] permanent link