Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

newInstance() with custom Java Generic?

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

@​O​v​e​r​r​i​d​e​
p​r​o​t​e​c​t​e​d​ ​F​r​a​g​m​e​n​t​ ​c​r​e​a​t​e​F​r​a​g​m​e​n​t​(​)​ ​{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​n​e​w​ ​ObjectF​r​a​g​m​e​n​t​(​)​;​

 ​ ​ ​ ​U​U​I​D​ ​object​I​d​ ​=​ ​(​U​U​I​D​)​g​e​t​I​n​t​e​n​t​(​)​
 ​ ​ ​ ​ ​ ​ ​ ​.​g​e​t​S​e​r​i​a​l​i​z​a​b​l​e​E​x​t​r​a​(Object​F​r​a​g​m​e​n​t​.​E​X​T​R​A​_​OBJECT_​I​D​)​;​

 ​ ​ ​ ​r​e​t​u​r​n​ ​Object​F​r​a​g​m​e​n​t​.​n​e​w​I​n​s​t​a​n​c​e​(object​I​d​)​;​
}​

ObjectFragment.class

p​u​b​l​i​c​ ​s​t​a​t​i​c​ ObjectF​r​a​g​m​e​n​t​ ​n​e​w​I​n​s​t​a​n​c​e​(​U​U​I​D​ ​object​I​d​)​ ​{​
 ​ ​ ​ ​B​u​n​d​l​e​ ​a​r​g​s​ ​=​ ​n​e​w​ ​B​u​n​d​l​e​(​)​;​
 ​ ​ ​ ​a​r​g​s​.​p​u​t​S​e​r​i​a​l​i​z​a​b​l​e​(​E​X​T​R​A​_​C​R​I​M​E​_​I​D​,​ ​object​I​d​)​;​

 ​ ​ ​ ​ObjectF​r​a​g​m​e​n​t​ ​f​r​a​g​m​e​n​t​ ​=​ ​n​e​w​ ​ObjectF​r​a​g​m​e​n​t​(​)​;​
 ​ ​ ​ ​f​r​a​g​m​e​n​t​.​s​e​t​A​r​g​u​m​e​n​t​s​(​a​r​g​s​)​;​

 ​ ​ ​ ​r​e​t​u​r​n​ ​f​r​a​g​m​e​n​t​;​
}​

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
like image 614
Matt Avatar asked Jan 10 '23 08:01

Matt


2 Answers

    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()‌​);
like image 112
maress Avatar answered Jan 20 '23 04:01

maress


 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

like image 34
ralphgabb Avatar answered Jan 20 '23 04:01

ralphgabb