Friday, January 15, 2016

The Adapter in the DialogFragment with a Checkbox

[Update: It looks like the switches and xml code is necessary, but that I might not have had to make a custom layout to make the adapter respond right.  I'll clear things up as soon as I have it all straight.]

I changed the title of this post to make it sound like the ending of a game of Clue.

These are my notes, meant to help me remember the hours of thrashing it's taken to make a simple dialog in Android.  What a mess.

I made a dialog using a DialogFragment.  It was good.  I added an adapter that was connected to a List returned from a database.  Connected the onClick methods and everything worked.

Then, I wanted to add a checkbox to the row for each element in the Adapter list.  And things got weird.

The problem with Android is that there are too many options, choices, and configurations, each with myriad options, choices, and configurations.  It's a combinatoric nightmare at times, made worse by documentation that refuses to go into any topic with any real depth.  I shouldn't say any, but it feels like it.  It's rare for answers to come from the docs.  Or the books sitting next to me.  Or the internet.  Finding answers usually takes an incredible amount of detective work.

In order to make the DialogFragment work, I had to create my own dialog layout.  Then, I had to override onCreateView and manage the click in the DialogFragment.  So I had to inflate a layout, find the controls, and connect the actions with the methods.  The docs were okay, but kind of light, so it took a little while to get it all sorted out.  Especially since I wanted to just use the code in the AlertDialog.builder thingie, because it took me right to the edge of getting my interface developed.  But I couldn't find a way to make it work.

So I had to override and populate and test and document onCreateView with the custom setup.  More work, more risk, more bugs, more docs, more wasted time.  Not because I can't code, but because it's not clear from the docs when to use the builder and when to use onCreateView from the start.  The dialogs docs shows all kind of cool dialogs that look kind of like the one I wanted to make.  Why wouldn't I think that was the way to build a dialog when all the examples suggested that was all I'd need?

Fine.  Whatever.  Android.

I got it built, got it populated and then tried to use it.  The click didn't work.  It had been working in the other layout.  I figured it'd just be an easy fix to make the program respond to the click.  It wasn't.  I groveled docs until I found that in order to make the row respond to a click event, I had to add the following line to the RelativeLayout that held the controls for each row of the Adapter:

android:descendantFocusability="blocksDescendants"

Of course, why didn't I remember the descendantFocusability switch with the blocksDescendants option?  I can't tell if blocksDescendants is the affirmative or the negative, but I'll look it up again later when I really need to remember yet another detail out of the myriad details that is Android that I'll immediately forget because of all the complexity and inconsistencies.

But adding that switch thing only made the row respond to the click.  The CheckBox didn't respond to the click.  Turns out the CheckBox click has to be managed in the Adapter.  I've seen that one before, but it's been a while, so it took some more groveling through StackOverflow and Android's pathetic excuse for documentation (that frequently contains errors and omissions which require further research, as if developing for this train-wreck isn't time consuming enough.)

Then I read and remembered that I had to add the code to manage the click on the CheckBox in the Adapter.  Of course.  Now my object-oriented code is fragmented into two classes to handle a click event, and that requires duplication of effort as well as remembering that the response to one event happens in one place and the response to the other event happens in another in spite of them both looking like they're happening in one place.

I had to add the following magic line to the XML for the CheckBox that is a member of each row:

android:focusable="false"

Then my adapter had to implement:

implements CompoundButton.OnCheckedChangeListener

// Here's the full class declaration:
public class SpecialSettingsAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener {

And then the method had to be added:

@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { ...code... }


And then the parent has to be discovered, and the row id found, or the data needs to be tucked away in the setTag() method when created or recycled, and retrieved by the getTag() method on the click, because unlike the OnItemClickedListener, which gives you a little detail that makes it easy to work with the ListView, this method doesn't give you anything but whether the CheckBox is checked, and the CheckBox itself.  Like nobody using an adapter is going to associate a control with a row number.  I'm sure I'm missing a method that provides all the detail I need, but I've wasted so much time just trying to get this insanely trivial part of my program to work, I could care less right now.

No comments:

Post a Comment