Challenge 1 - Brings up a design question


#1

When I did the previous chapter (IO with JSON) I found a problem. If you go to the detail view to create a new Crime and then return to the list without entering a title, JSON throws an exception (when loading the file) because Crime.mTitle is NULL. I looked into this and found that a new Crime is created and added to the CrimeLab by CrimeListFragment before going to the detail view. Thus, there is no easy way to deal with the user changing their mind. I fixed it by changing saveCrimes():

[code]private void saveCrimes(ArrayList crimes, FileOutputStream out) throws JSONException, IOException {
// Build an array in JSON
JSONArray array = new JSONArray();
for (Crime c : crimes) {
if (c.getTitle() == null) {
c.setTitle(“None”); <— Change to “None” if NULL
}
array.put(c.toJSON());
}

… etc.[/code]

The challenge is making me wonder why CrimeListFragment doesn’t already have a way to only add a new Crime if the user at least entered a title for it. Now we are to add the ability of the user to view an existing Crime and delete it. I don’t see a contextual menu as being a good solution to this. The detail view should have Buttons: SAVE, CANCEL, DELETE. The CrimeListFragment should be able to handle handle situations where the use clicks one of the buttons, uses the android back button (maybe ask for confirmation to save changes or not if there are any, bringing up the question of how do you prevent a user from changing views (interrupt the android’s lifecycle)), and handle the situation where the user starts doing other things like, turn the phone off, start up another app that causes the OS to destroy CrimeFragment and CrimeListFragment and never goes back to our app.

So, for me this is a situation where the solution (use a context menu) is a bad design decision and doing it just to learn and understand the concept of how to implement contextual menus conflicts with the need to learn the how/why/when such a feature would be used.

It has bugged me for a while that we can add an empty Crime, the IO JSON thing actually causes it to require code to fix it, and now there is this other issue.

Do you know what I mean by this? How learning about something specific with a wrong usage for it makes the learning harder?

Thanks.

EDIT: Ooops! I was actually attempting to have CrimeFragment use a context menu when I realized (after cutting and pasting the code in onCreateView() and realizing that CrimeFragment does not have a list view) that the challenge is to use an Options Menu or Action Bar (not a context menu). Sorry about that. :blush:

EDIT2: Now I am thinking this challenge belongs in Chapter 16. I automatically assumed it would apply to what we learned in this chapter. It has nothing to do with this chapter.


#2

Happy 4th!

I am still wondering how this should be handled. In my first post I think I made the mistake of thinking of the detail view as a child of CrimeListFragment and that CrimeListFragment should control when a Crime is added/deleted from the list, and that CrimeFragment should send something in the Intent back to CrimeListFragment in situations where the user deletes a Crime, leaves that view without changing anything in the defauilt Crime that has already been added to the list, or clicks the cancel button.

Now I am thinking that CrimeFragment should get access to CrimeLab to delete a Crime under those conditions. For leaving the view, CrimeFragment could check the Crime.mTitle for null in onDestroy() and delete it there. For the cancel button, a callback for the cancel button would do the delete and then navigate back to CrimeListFragment.

So far we have coded the following:

in onListItemClick() - [color=#800000]startActivity(i);[/color]
in the subroutine to create a new empty Crime and start CrimeFragment - [color=#800000]startActivityForResult(i, 0);[/color]

But we haven’t yet added the routine [color=#800000]onActivityResult()[/color].

So, I don’t know yet if we are going to add [color=#800000]onActivityResult()[/color] eventually or not.

Thanks.


#3

For some reason when I create a crime without a title I do NOT get an exception and the app continues and works fine. Wonder why?


#4

It may be that you noted the errata item for this, where we fixed it? Or perhaps you got the brand new updated e-edition where we fixed it?


#5

Ah yes, the change back from Chap 17 in the Crime constructor for a JSONobject - yep that’s why it works :wink:

I find reading through the posts others make very informative in making sure I understand what is going on, so I chase these things down like a dog searching for a bone :wink:

Actually I have to say that generally if a field should not be blank or null, it should be validated when the user performs the “form” input - in that case the user should not be able to “finish” the CrimeFragment without a user alert or at the minimum some lazy default data value operation as suggested above depending on your design philosophy for the UI element.

What would be the “proper” way of alerting the user that the Title was required when the user either hits the back button, the “up” caret on the action bar, or home button leaving the activity/fragment? I guess I’m asking for 2 things - one what would you have to override to pickup trap the user activity completely to require the input, and how would you alert the user, using an alert dialog or toast?

I am guessing onActivityResult is too late. If you checked the Crime title in onPause() for the fragment could you actually drive the fragment back to active (onResume) state to force the user to complete a field to your satisfaction? What is the typical way this would be handled? There has to be a way to do this without holding the device hostage in the fragment :wink:


#6

That’s actually a very interesting question. Form validation is tied to a very specific flow - it assumes that before the user’s input is committed to persistent storage, it must be analyzed for inconsistencies or flaws.

The standard mobile app interaction model doesn’t allow an app to assume this. The standard app model - what we show in the book - is that persistence just happens. There are no save buttons, which means there isn’t a natural place to stop and do a validation.

Of course, lots of apps need form validation, too. Sticking with the typical mobile app interaction model, a good solution would be to add an editing screen to the flow. Whatever the user sees on the editing screen is not saved to the data store; if the user hits the back button, their changes are discarded, but if the save button is tapped the new or edited item is saved.

I’m not a designer, though. I’m sure there are other solutions to the problem.


#7

Thanks for the response, thats kind of what I thought. At this point in the CriminalIntent example it’s not clear whether the CrimeFragment IS the “new” crime screen, the edit screen, or whether it is the “view fragment” screen. It is kind of a combo at the moment. If there were a bunch more info to see not in the list view I would think clicking on a crime in the listview should take you to a Crime view without interactive fields, which itself would have an edit button on the action bar or options menu which enables the fields to be touched. It is definitely a design issue for flow - the direct setting of the model info in the view is where the problem arises - I have always been told that the model should perform the data validation, and would provide methods to the controller which would use them to validate and control the view presentation. There are tradeoffs both ways…