Java tutorial
/* * Copyright 2015 Nick Tsygankov (nicktgn@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.nicktgn.mvp; import android.os.Bundle; import android.support.v4.app.Fragment; import android.util.Log; import com.noveogroup.android.log.Logger; import com.noveogroup.android.log.LoggerManager; import java.lang.reflect.InvocationTargetException; /** * Abstract helper implementation of the View based on {@link Fragment}. Actual view * fragments can extend from this class. * @author nicktgn */ public abstract class MvpFragment<V extends MvpView, P extends MvpPresenter> extends Fragment implements MvpView { private static final Logger logger = LoggerManager.getLogger(MvpAppCompatActivity.class.getName()); protected P presenter; MvpBundle stateData = null; MvpBundle argumentsData = null; /** * Use this helper method to get another View (Fragment) * with extras containing provided arguments indented for Presenter of this new View * @param arguments arguments from this View's Presenter intended for Presenter of another View * @return intent to another View (Activity) (or null if failed to instantiate) */ protected <T extends MvpFragment> T getMvpFragment(Class<T> targetView, MvpBundle arguments) { try { T fragment = targetView.getConstructor().newInstance(); Bundle bundle = new Bundle(); bundle.putBundle(Constants.ARGUMENTS_DATA, arguments.getRealBundle()); fragment.setArguments(bundle); return fragment; } catch (java.lang.InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); logger.d("onActivityCreated"); presenter = createPresenter(); // ---- INPUT ARGUMENTS ---- // if (argumentsData != null) { try { // first try to get input model data from fragment arguments // NOTE: you can still skip this convenience mechanism, and inject the data into presenter // through presenter's constructor for example Bundle bundle = getArguments().getBundle(Constants.ARGUMENTS_DATA); if (bundle != null) { argumentsData = new MvpBundle(bundle); logger.d("Got arguments data from fragment arguments"); } // if noting found in arguments, try to get input model data from Intent // (that started Activity hosting this Fragment) // NOTE: you can still skip this convenience mechanism, and inject the data into presenter // through presenter's constructor for example else { bundle = getActivity().getIntent().getExtras().getBundle(Constants.ARGUMENTS_DATA); if (bundle != null) { argumentsData = new MvpBundle(bundle); logger.d("Got argumnets data from intent"); } } } catch (NullPointerException e) { logger.d("No arguments data"); } } // ---- CACHING ---- // // if we have savedInstanceState (activity was re-created) if (savedInstanceState != null) { Bundle bundle = savedInstanceState.getBundle(Constants.CACHED_STATE_DATA); if (bundle != null) { stateData = new MvpBundle(bundle); logger.d("Got cached state data from instance state"); } } // else this fragment is just created or came back from back stack // try to restore presenter state from MvpState (cause fragment instance is still // the same and only the view was re-created) else { stateData = MvpState.restoreState(this); if (stateData != null) { logger.d("Got cached data from mvp fragment state"); } } presenter.attachView(this, argumentsData, stateData); } @Override public void onDestroyView() { logger.d("onDestroyView"); // in case the fragment is not destroyed (that is when its returned from back stack) // and only view is recreated, save presenter state in MvpState (cause we retain fragment // instance reference) MvpBundle savedData = presenter.saveState(); if (savedData != null) { MvpState.saveState(this, savedData); } presenter.detachView(getRetainInstance()); super.onDestroyView(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); MvpBundle savedData = presenter.saveState(); if (savedData != null) { outState.putBundle(Constants.CACHED_STATE_DATA, savedData.getRealBundle()); } } abstract protected P createPresenter(); }