Working with Existing Runs - Huh?


#1

Book:

But then you proceed to reuse RunActivity for this. The end result is you get a display of RunFragment with the UI fields filled in for the last Location in the Run. You can click the Start button and it will start appending new locations to the existing Run. and stop doing this when the Stop button is clicked.

I’m lost. Why would we reuse RunActivity for this? Why would we want the user to be able to start adding new locations to an existing run? I can maybe see a need for the user to stop recording new locations (to eat or sleep) and then restart the recording later, but that would require more intelligence in the app to know when a run is completed or to be continued.

Why don’t we want a view where the user could edit the run, deleting locations that are redundant or not wanted, or to delete the entire run? This would allow us to see how SQLite deletes are performed at the different levels.

BTW, I am surprised that I am the only one giving you feedback like this. Does anyone else reading this book question anything (other than errata)?

Thanks.


#2

One more thing…

If I start a new Run, then go to the list of existing runs and select one, then start/stop that Run, the one call to RunManager.stopLocationUpdates() causes the app to unregister for receiving location updates for the new Run that was left running too.


#3

First post first:

The idea of editing, adding and removing points is a nifty one. We’re naturally limited in how much we can reasonably elect to do in our examples, so while we might politely ask to steal your idea for a Challenge, we probably don’t have the space to implement such a thing.

I agree that adding locations to the end of the run is a little odd. A natural fix would be add code to set the run in stone once it has stopped.

Finally, as far as being surprised about nobody else offering feedback… well, here’s the deal.

See, all of us here on earth are born as we are and live as we live. And once we make it to a certain place in our lives, everything we do seems perfectly natural and obvious. And rightly so - once you’ve been running around for twenty or thirty years, you’re bound to find your own ways of doing things which seem comfortable and easy, sensible and strong.

Of course, to other people, these ways of doing things may seem very unusual indeed. They might think, “Why would anyone spend their time doing anything other than finding straightforward answers to simple questions?” But they’re not you, are they?

My coworkers at Big Nerd Ranch can testify to this: the world is probably better off with only one Bill Phillips, not six billion of them. Likewise, if every question we received here demanded as much thought as yours do, Rick, I would probably run away and build a cabin in the woods.


#4

And as far as the second post goes, I have to confess that it’s a flaw in the architecture of the app. This is another reason that I think that making it so that Runs can only be recorded once makes a lot of sense.


#5

OK. Thanks. 17 years of assembler programming (and generating many business and general designs) in a place that is not very tolerant of mistakes has given me OCD. Trying to learn a whole new language and platform, where so much stuff is done for you, when I am used to coding everything at just above the machine level is a challenge. I can’t help but wonder how it works behind the scenes. Thankfully, I don’t find OOP hard to understand at all.

The issue from post #2 disappeared when I went to do the challenge. Not sure why. At first, I thought it was because I modified RunCursorAdapter to be non-static, so I could do a getActivity() in it. But then I undid my changes and it continued working right. The buttons are now disabled when viewing one Run when another is still running. So, you can’t do anything to a Run until you stop the other one.

I found more info on inner static classes on StackOverflow. However, I ended up doing this to make my challenge work:

Have RunCursorAdapter save the context passed in the constructor.

Then do this in bindView():

if (RunManager.get(mContext).isTrackingRun(run)) { startDateTextView.setTextColor(Color.RED); } else { startDateTextView.setTextColor(Color.BLACK); }

The only other change needed was in onListItemClick() (so the adapter gets invalidated when you return to the list.

//startActivity(i); startActivityForResult(i, REQUEST_NEW_RUN);

Is having RunCursorAdapter save the Context better than making it non-static and just putting getActivity() where mContext is?

Thanks.

I wish I could live in a cabin in the woods, instead of trying to learn this new stuff so I can get a job again. But damn if I don’t have expensive needs. :mrgreen:


#6

There are arguments to made for both design choices. There’s definitely nothing wrong with having the cursor adapter hold on to the context. (CursorAdapter does this itself under the hood. I don’t know why it doesn’t have a getContext() getter like ArrayAdapter does.)

The upside to a non-static Adapter inner class is that it can integrate more tightly with its enclosing controller. The downside is, well… that it’s then integrated more tightly with its enclosing controller. I usually just let it be a tightly coupled inner class, because I find that it usually ends up being that way anyway.


#7

Thanks. I read somewhere on the internet (so you know it has to be true :wink: ) that when it is not static it keeps a pointer to its Activity, which could cause memory leaks. I don’t know under what circumstances this would occur tho.

I changed the following instruction in RunFragment.updateUI()

[code]mStopButton.setEnabled(started && trackingThisRun);

to

mStopButton.setEnabled(trackingThisRun);[/code]

It seems to work the same (stop button only enabled for the Run being tracked), and I haven’t been able to create a situation where one would be off for the Run being tracked or trackingThisRun being true for another Run.


#8

That’s true about it leaking the Activity, but you would have to pass the ArrayAdapter to something else besides the ListView for that to happen.


#9

LOL feeling your pain Rick - fellow OS low level programmer for 30 years here and truly no one would structure a real app that way. I would have a different activity/fragment or dialog that presents not just the runs last location but all the loc records for a “done” run. Also notice this chapter used the cheap options menu not the action bar although we know the start or new run should be on the action bar post-Honeycomb. Also a “delete run” selection from the listview or the runactivity would be nice. I think the idea of allowing the user to go back to the list while a run is in progress creates a world of modality problems for the UI…

Anyway, like you I take a chill pill and realize each chapter gives us a few more tools for the apps we want to write, and try not to be the one to gripe at Wade too much. After all their book really kills all the others, and after you go through this book, I have found using all the other online android sites, books, and refs much more understandable.

I think generally the MOST disappointing thing about Android overall is how crappy Google’s Android API documentation is - not much more than the syntax of methods and a one liner, not real examples in many cases nor is there any full explanation of each parameter in each method to the level of detail we always provided app writers in operating systems I have developed. When Wade said it helps to get used to reading the open source Android code that told me all I needed to know - this thing is VERY poorly documented.

Wade I am curious how would you grade the API documentation of Android versus that available for Apple iOS?

Also which is more difficult to come up to speed on? (I am particularly interested from the non OOP viewpoint of experience since one is Java based and the other ObjC)