I am working on my first 'Non-tutorial' application to grow and strengthen my Android development skill sets.
I've been using lots of Java Generics to enhance reusability and debugging, especially since lots of my fragments do the same thing with subclasses of a Question
class.
I just ran across a conventional pattern that is new to me and was wondering if I can apply it to Generic Classes in Java.
According to the text, a newInstance(args,...)
method should be created within Fragment classes to handle the transition of Intent Extras to Fragment Arguments.
Example:
SomeActivity.class
@Override
protected Fragment createFragment() {
return new ObjectFragment();
UUID objectId = (UUID)getIntent()
.getSerializableExtra(ObjectFragment.EXTRA_OBJECT_ID);
return ObjectFragment.newInstance(objectId);
}
ObjectFragment.class
public static ObjectFragment newInstance(UUID objectId) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_CRIME_ID, objectId);
ObjectFragment fragment = new ObjectFragment();
fragment.setArguments(args);
return fragment;
}
Excerpt From: Brian Hardy. “Android Programming: The Big Nerd Ranch Guide.”
But what about cases using Java Generics?
Code I am working on:
QuestionListActivity.class
public class QuestionListActivity extends SingleFragmentActivity {
// CONSTANTS
public static final String EXTRA_FRAGMENT_TYPE = "com.renaissanceartsmedia.flashcard.editquestionactivity.fragment";
public static final String EXTRA_ACTIVITY_TITLE = "ListQuestionActivity.EXTRA_ACTIVITY_TITLE";
public static final String TAG = "QuestionListActivity";
// Member Properties
QuestionType mFragmentType;
@Override
protected Fragment createFragment() {
mFragmentType = (QuestionType) getIntent().getSerializableExtra(EXTRA_FRAGMENT_TYPE);
System.out.println("mFragmentType: " + mFragmentType);
// Switch on Enumeration
switch (mFragmentType) {
case MULTIPLE_ANSWER_QUESTION:
case MULTIPLE_CHOICE_QUESTION:
case TRUE_FALSE_QUESTION:
// PREVIOUS METHOD
//return new QuestionListFragment<MultipleAnswerQuestion>();
// Attempting to refactor to newInstance(Bundle args)
return QuestionListFragment<MultipleAnswerQuestion>.newInstance(getIntent().getExtras()); // ERROR
case MATCHING_QUESTION:
return new QuestionListFragment<MatchingQuestion>();
case BLANK_QUESTION:
//return new BQFragment();
return new QuestionListFragment<BlankQuestion>();
default:
return new QuestionListFragment<Question>();
}
}
}
Currently, I am getting the Extras from within the QuestionListFragment's onCreate() method. I know that I will remove this code if transitioning to the newInstance() convention should be used with Java Generics.
QuestionListFragment.class
public class QuestionListFragment<E extends Question> extends ListFragment implements QuestionDialogInterface {
// Constants
public static final String TAG = "QuestionListFragement";
public static final String DIALOG_TITLE = "QuestionListFragment.DIALOG_TITLE";
public static final String DIALOG_MESSAGE = "QuestionListFragment.DIALOG_MESSAGE";
public static final String QUESTION_TYPE = "QUESTION_TYPE";
private static final int DIALOG_FRAGMENT = 1;
// Member Properties
Flashcard mFlashcard;
QuestionType mQuestionType;
String mActivityTitle;
ArrayList<E> mQuestions;
DialogFragment mDialogFragment;
// SOMETHING LIKE THIS???
@SuppressWarnings({ "unchecked", "rawtypes" })
public static QuestionListFragment<? extends Question> newInstance(Bundle args) {
// Create a new instance of QuestionListFragment<? extends Question>
QuestionListFragment<? extends Question> fragment = new QuestionListFragment();
// Set the arguments
fragment.setArguments(args);
// Return the Fragment
return fragment;
}
@SuppressWarnings("unchecked")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"Enter onCreate(Bundle savedInstanceState)");
// Enable Options Menu
setHasOptionsMenu(true);
// Create the ActionBar 'UP' Button
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
// The Intent Extras
Bundle extras = getActivity().getIntent().getExtras();
// Extract the Flashcard from the extras
UUID flashcardId = (UUID) extras.getSerializable(Flashcard.EXTRA_FLASHCARD_ID);
mFlashcard = FlashcardStore.get(getActivity()).getFlashcard(flashcardId);
mQuestionType = (QuestionType) extras.getSerializable(EditQuestionActivity.EXTRA_FRAGMENT_TYPE);
mActivityTitle = extras.getString(QuestionListActivity.EXTRA_ACTIVITY_TITLE);
// Get a Container of Multiple Answer Questions
mQuestions = (ArrayList<E>) mFlashcard.getQuestions(mQuestionType);
// Set the Title of the Fragment's Activity
getActivity().setTitle(mActivityTitle);
// Create a list
ListItemLayoutAdapter adapter = new ListItemLayoutAdapter(mQuestions);
// Set the adapter for the list
setListAdapter(adapter);
Log.d(TAG,"Exit onCreate(Bundle savedInstanceState)");
}
....
}
What are Best Practices in regards to Android Fragments and Java Generics? Can someone describe what they are, why they should be used. If newInstance() should be used, please help me fix the error by providing the correct syntax for declaring:
// Attempting to refactor to newInstance(Bundle args)
return QuestionListFragment<MultipleAnswerQuestion>.newInstance(getIntent().getExtras()); // ERROR
public static <T extends Question> QuestionListFragment<T> newInstance(Bundle args) {
// Create a new instance of QuestionListFragment<? extends Question>
QuestionListFragment<T> fragment = new QuestionListFragment<T>();
// Set the arguments
fragment.setArguments(args);
// Return the Fragment
return fragment;
}
and then to call it:
QuestionListFragment.<MultipleAnswerQuestion>newInstance(getIntent().getExtras());
public static <T extends BaseFragment> T getInstance (Class<T> mClass, Bundle args) {
try {
T instance = mClass.newInstance();
instance.setArguments(args);
return instance;
} catch (java.lang.InstantiationException | IllegalAccessException e) {
/**
* Error thrown
*/
}
return null;
}
A shorter version. Cheers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With