Java tutorial
/* * ZenFramework for Android * * :copyright: (c) 2013-2016 by Marco Stagni, Giovanni Barillari * :license: GPLv3, see LICENSE for more details. */ package io.amira.zen.core; import android.support.v4.app.Fragment; import android.os.Bundle; import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import com.google.android.gms.maps.GoogleMap; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import io.amira.zen.geo.ZenMap; import io.amira.zen.layout.ZenViewProxy; public abstract class ZenFragment extends Fragment { //: parameters are injected by Zen protected List<Object> parameters = new ArrayList<Object>(); //: current is stored on instance savings. MUST contains only serializable protected Map<String, Object> current = new HashMap<String, Object>(); //: class basic variables, injected by Zen private String title; private int layoutId; //: reference to Fragment view, inited looking at layoutId private View rootView; //: Zen support to resources (in views) private Map<String, Integer> _res; //: Google maps support vars public boolean hasMap = false; private ZenMap mapFrag; protected GoogleMap map; private int mapContainerId; //: booleans needed by Zen to collect Fragment state private boolean isNew = true; private boolean isResumed = false; //: public method to gain Fragment title public String getTitle() { return title; } //: empty constructor (gi0baro: do we need that?) public ZenFragment() { } //: set Fragment base variables, called by Zen public void setVariables(String title, Integer layoutId) { //ZenLog.l("SETTING VARIABLES " + title + " - " + ((Object) this).getClass().getCanonicalName()) ; this.title = title; this.layoutId = layoutId; } //: save current and layout on suspensions (needed for restore) @Override public void onSaveInstanceState(Bundle outState) { //ZenLog.l("Saving FRAGMENT STATE"); super.onSaveInstanceState(outState); outState.putInt("layoutid", this.layoutId); outState.putSerializable("current", (Serializable) current); } //: load view defined by layoutId, init helpers @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { try { //long p = System.nanoTime(); //ZenLog.l("CREATING VIEW "+((Object) this).getClass().getCanonicalName()); //ZenLog.l(this.layoutId); if (savedInstanceState != null) { //ZenLog.l("RESUMING FRAGMENT"); isResumed = true; isNew = false; if (this.layoutId == 0) { //ZenLog.l("RELOADING LAYOUT ON RESUME"); this.layoutId = savedInstanceState.getInt("layoutid"); current = (HashMap<String, Object>) savedInstanceState.getSerializable("current"); } } else { isResumed = false; isNew = true; } //ZenLog.l(this.layoutId); rootView = inflater.inflate(layoutId, container, false); _res = new HashMap<String, Integer>(); //long d = System.nanoTime(); //ZenLog.l("TIME to inflate view "+(d-p)); } catch (NullPointerException e) { e.printStackTrace(); return null; } //: load parameters from Zen parameters = ZenApplication.navigation().getParameters(); //: always launch preLoad method preLoad(); //: if Fragment is resumed, we load helpers now (otherwise we'll wait for animations) if (!isNew) { //ZenLog.l("FRAGMENT NOT NEW"); getElements(); buildElements(); } return rootView; } //: ensure memory cleaning for custom view implementation @Override public void onDestroyView() { super.onDestroyView(); rootView = null; } //: useful shortcut find views in Fragment layout public Object findViewById(int id) { return rootView.findViewById(id); } //: provides access to resources public ZenViewProxy res(String id) { if (!_res.containsKey(id)) { int vid = ZenResManager.getResourceId(id); _res.put(id, vid); } return new ZenViewProxy(_res.get(id), rootView); } //: override of animation on Fragment creation, load helpers if needed @Override public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { if (nextAnim != 0) { Animation anim = AnimationUtils.loadAnimation(getActivity(), nextAnim); anim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (isNew) { getElements(); buildElements(); isNew = false; } renderMap(); } @Override public void onAnimationRepeat(Animation animation) { } }); return anim; } else { return super.onCreateAnimation(transit, enter, nextAnim); } } //: Zenfragment helpers // : preLoad is called on fragment creation public void preLoad() { } // : getElements and buildElements are called consequentially after Zen animations or resume public void getElements() { }; public void buildElements() { }; //: useful shortcuts to send parameters to another Fragment via Zen public static void sendParameters(Object o) { List<Object> parameters = new ArrayList<Object>(); parameters.add(o); ZenApplication.navigation().setParameters(parameters); } public static void sendParameters(Object[] o) { List<Object> parameters = new ArrayList<Object>(); for (int i = 0; i < o.length; i++) { parameters.add(o[i]); } ZenApplication.navigation().setParameters(parameters); } public static void sendParameters(List<Object> o) { ZenApplication.navigation().setParameters(o); } //: Google Maps methods - except for strange uses, user should override only setMap // : used to add a map on fragment, shoud be called in preLoad() helper public void addMap(int containerId) { hasMap = true; mapContainerId = containerId; } // : setup map fragment ensuring activity is loaded @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (hasMap) { setMapFrag(); } } // : ensure map rendering on Fragment resume @Override public void onResume() { super.onResume(); if (hasMap) { loadMap(); if (isResumed) { renderMap(); } } } // : detach the map from fragment on detach (needed on old Android versions to avoid view errors) @Override public void onDetach() { super.onDetach(); if (hasMap) { detachMap(); } } // : this create the map Fragment inside the container defined by user public void setMapFrag() { getActivity().runOnUiThread(new Runnable() { @Override public void run() { FragmentManager fm = getChildFragmentManager(); mapFrag = (ZenMap) fm.findFragmentById(mapContainerId); if (mapFrag == null) { //ZenLog.l("MAP FRAGMENT NULL: CREATING IT"); mapFrag = ZenMap.create(); fm.beginTransaction().add(mapContainerId, mapFrag).commit(); // fix map = null; } } }); } // : load the map public void loadMap() { if (map == null) { map = mapFrag.getMap(); } } // : called by zen to load user's options public void renderMap() { if (map != null) { setMap(); } } // : user should override this method to set preferences/load data on map public void setMap() { map.setMyLocationEnabled(true); } // : ensure cleaning and avoid layout errors public void detachMap() { try { Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); childFragmentManager.setAccessible(true); childFragmentManager.set(this, null); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } map = null; mapFrag = null; } }