Adding onCrimeDeleted() to CrimeListFragment.Callbacks

Hi folks, I’m wondering if I’m a stylish Android programmer with my implementation of deleting a Crime in the two-pane context. I added delete in two different ways:

  1. from the option menu, where it pops up a NumberPicker dialog similar to the DatePicker dialog, where the user picks the number of the crime to delete
  2. From a long press on a Crime in the list, which pops up an AlertDialog to verify that the user wants to delete the crime.

Either way presented a problem: If I delete a Crime out of the list that is currently being displayed in the detail, I have to remove it from the detail. I solved it by adding onCrimeDeleted() to the CrimeListFragment.Callbacks and implemented it similarly to the onCrimeSelected method in CrimeListActivity. I checked for the presence of detail_fragment_container and only took action if it was present.

There were two problems:

  1. I didn’t know which Crime was being displayed in the detail, so I didn’t know if I had to remove it.
  2. In order to remove the fragment from the detail, I needed the fragment itself – the FragmentTransaction remove() method takes a Fragment.

The solution: tags

To solve #1, I noticed that the View class has a setTag()/getTag() pair that can attach an object to a View and retrieve it later. So I picked the crime_suspect Button at semi-random and attached the Crime Id to it at creation:

mSuspectButton = (Button) view.findViewById(R.id.crime_suspect);
mSuspectButton.setTag(mCrime.getId());  // used to identify the crime in CrimeListActivity.onCrimeDeleted()
mSuspectButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View pView) {
            startActivityForResult(pickContact,REQUEST_CONTACT);
        }
});

To solve #2 I noticed that the FragmentTransaction class has a replace() method that takes a String as a tag, so it can be retrieved later by FragmentManager.findFragmentByTag(String). So I added the tag to the replace() call in onCrimeSelected():

public void onCrimeSelected(Crime pCrime) {
    if (findViewById(R.id.detail_fragment_container) == null) {
        Intent intent = CrimePagerActivity.newIntent(this, pCrime.getId());
        startActivity(intent);
    } else {
        Fragment newDetail = CrimeFragment.newInstance(pCrime.getId());
        getSupportFragmentManager().beginTransaction()
            .replace(R.id.detail_fragment_container, newDetail, DETAIL_FRAGMENT_TAG)
            .commit();
    }
}

With those two pieces of data, I was able to write onCrimeDeleted(Crime). It retrieves the Crime Id from the crime_suspect Button and checks to see if it is in the database. If it is, it retrieves the Fragment by calling findFragmentByTag, passing it the tag the Fragment was created with. It then deletes the Fragment from the view.

public void onCrimeDeleted(Crime pDeletedCrime) {
    View dfc = findViewById(R.id.detail_fragment_container);
    if (dfc != null) {
        Button crimeSuspect = (Button) findViewById(R.id.crime_suspect);
        UUID uuid = (UUID) crimeSuspect.getTag();  // We attached UUID of crime upon creation
        if (pDeletedCrime.getId().equals(uuid)) {  // Does deleted crime match detail crime?
            FragmentManager fm = getSupportFragmentManager();
            Fragment detailFragment = fm.findFragmentByTag(DETAIL_FRAGMENT_TAG);
            fm.beginTransaction()
                    .remove(detailFragment)
                    .commit();
        }
    }
}

It works, but my question is: Is this the “correct” way to do it? Is there another better way that minimizes the linkage between the parts better than this?

Thanks for reading!

1 Like