Challenge: Deleting Crimes by using an interface

Here’s my solution to the Deleting Crimes challenge. The following guide on communicating with fragments helped me out: https://developer.android.com/training/basics/fragments/communicating.html

I’m assuming that you know how to create the Delete Crime action in the toolbar.

In CrimeFragment I created an interface for CrimeFragment to communicate with CrimePagerActivity in order to delete the crime.

public class CrimeFragment extends Fragment {

OnDeleteCrimeListener mCallback;

public interface OnDeleteCrimeListener {
public void onCrimeIdSelected (UUID crimeId);
}

Here is where onCrimeIdSelected is called by CrimeListFragment using the interface that is implemented in CrimePagerActivity:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.delete_crime:
            mCallback.onCrimeIdSelected(mCrime.getId());
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

onCrimeIdSelected is implemented in CrimePagerActivity as follows:

public class CrimePagerActivity extends AppCompatActivity
implements CrimeFragment.OnDeleteCrimeListener {

public void onCrimeIdSelected (UUID crimeId) {
Intent data = new Intent();
data.putExtra(EXTRA_CRIME_ID, crimeId);
setResult(Activity.RESULT_OK, data);
finish(); // CrimePagerActivity
}

The call to finish() will close the CrimePagerActivity.

In CrimeListFragment I changed startActivity(…) to startActivityForResult(…).

@Override
public void onClick(View view) {
Intent intent = CrimePagerActivity.newIntent(getActivity(), mCrime.getId());
startActivityForResult(intent, REQUEST_CRIME);
}

The call to startActivityForResult(…) will make sure that CrimeListFragment and CrimePagerActivity can communicate with each other when it is time to delete the crime._

and finally, in CrimeListFragment.java.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != Activity.RESULT_OK) {
        return;
    }
    if (requestCode == REQUEST_CRIME) {
        if (data == null) {
            return;
        }

        UUID crimeId = (UUID) data.getSerializableExtra(CrimePagerActivity.EXTRA_CRIME_ID);
        CrimeLab crimeLab = CrimeLab.get(getActivity());
        Crime crime = crimeLab.getCrime(crimeId);
        crimeLab.deleteCrime(crime);
    }
}

The end.

3 Likes

Your solution was very helpful in getting this challenge working for me. However, I think you might also need to initialize mCallback when its attached. I did this by overriding the onAttach method in CrimeFragment.java:

@Override
public void onAttach(Context context) {
super.onAttach(context);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnDeleteCrimeListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnDeleteCrimeListener");
}
}

Don’t forget to add the request code in CrimeListFragment.java:

private static final int REQUEST_CRIME = 0;

Lastly, this is the deleteCrime method that I used in CrimeLab.java. There are more efficient ways of doing it, but it works:

public void deleteCrime(Crime c) {
for(int i = 0; i < mCrimes.size(); i++) {
if(mCrimes.get(i).getId() == c.getId()) {
mCrimes.remove(i);
return;
}
}
}

P.S. I also had trouble when my menu wouldn’t show up and I couldn’t figure out why. Turns out I forgot to add the setHasOptionsMenu(true); line to the onCreate method in CrimeFragment.java:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}

Just a heads up for anyone that might be having the same problem :+1:t5:

1 Like