Java tutorial
package it.rainbowbreeze.keepmoving.ui; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.Button; import android.widget.TextView; import javax.inject.Inject; import it.rainbowbreeze.keepmoving.R; import it.rainbowbreeze.keepmoving.common.ILogManager; import it.rainbowbreeze.keepmoving.common.Utils; import it.rainbowbreeze.keepmoving.domain.Route; import it.rainbowbreeze.keepmoving.logic.PositionManager; /** * This file is part of KeepMoving. KeepMoving is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * <p/> * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * <p/> * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * <p/> * Copyright Alfredo Morresi * <p/> * Created by Alfredo "Rainbowbreeze" Morresi on 02/07/14. */ /** * A fragment representing a list of Items. * <p /> * Large screen devices (such as tablets) are supported by replacing the ListView * with a GridView. * <p /> * Activities containing this fragment MUST implement the {@link it.rainbowbreeze.keepmoving.ui.TimetableFragment.OnFragmentInteractionListener} * interface. */ public class TimetableFragment extends Fragment implements AbsListView.OnItemClickListener { private static final String LOG_TAG = TimetableFragment.class.getSimpleName(); // Position of the fragment in the Page adapter private static final String ARG_POSITION = "FragmentPosition"; @Inject protected ILogManager mLogManager; private OnFragmentInteractionListener mListener; private int mFragmentPos; // The fragment's ListView/GridView. private AbsListView mListView; // The Adapter which will be used to populate the ListView/GridView with Views. private StepsArrayAdapter mAdapter; private TextView mLblRemainingTime; private TextView mLblArrivalTime; private boolean mRegisteredReceiver; private boolean mFirstDrawDone; // TODO making the injection mechanism working public static TimetableFragment newInstance(int fragmentPos, ILogManager logManager, PositionManager positionManager) { TimetableFragment fragment = new TimetableFragment(); Bundle args = new Bundle(); args.putInt(ARG_POSITION, fragmentPos); fragment.setArguments(args); fragment.mLogManager = logManager; logManager.d(LOG_TAG, "Created fragment for pos " + fragmentPos); return fragment; } /** * Mandatory empty constructor for the fragment manager to instantiate the * fragment (e.g. upon screen orientation changes). */ public TimetableFragment() { } @Override public void onAttach(Activity activity) { super.onAttach(activity); // Here mFragmentPos is still not available mLogManager.d(LOG_TAG, "onAttach to activity " + activity); try { mListener = (OnFragmentInteractionListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mFragmentPos = getArguments().getInt(ARG_POSITION); } mFirstDrawDone = false; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mLogManager.d(getLogTag(), "OnCreateView fragment views"); View view = inflater.inflate(R.layout.fra_timetable, container, false); // Sets the ListView and the adapter mAdapter = new StepsArrayAdapter(getActivity()); mListView = (AbsListView) view.findViewById(R.id.timetable_lstSteps); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(this); mLblArrivalTime = (TextView) view.findViewById(R.id.timetable_lblArrivalTime); mLblRemainingTime = (TextView) view.findViewById(R.id.timetable_lblRemainingTime); ((Button) view.findViewById(R.id.timetable_btnSendToWatch)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendToWear(); } }); // The activity calls the method to update the fragment, but sometimes fragment is still // not attached if (!mFirstDrawDone) { mLogManager.d(getLogTag(), "Forcing a first draw of the fragment"); updateUIViews(true); } return view; } /** * Send to Android wear */ private void sendToWear() { mListener.sendToWear(mFragmentPos); } @Override public void onDestroyView() { super.onDestroyView(); mLogManager.d(getLogTag(), "OnDestroyView fragment"); mFirstDrawDone = false; } @Override public void onDetach() { super.onDetach(); mLogManager.d(getLogTag(), "Detaching from activity " + mListener); mListener = null; } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (null != mListener) { // Notify the active callbacks interface (the activity, if the // fragment is attached to one) that an item has been selected. //mListener.onFragmentInteraction(DummyContent.ITEMS.get(position).id); } } /** * Updates all the UI element that show some sort of time counter */ public void updateUIViews(boolean fullUpdate) { if (fullUpdate) { mLogManager.d(getLogTag(), "Updating all the views"); Route route = getRoute(); mAdapter.setNotifyOnChange(false); mAdapter.clear(); // A route always has steps, otherwise what kind of route is? mAdapter.addAll(route.getSteps()); //addAll automatically calls notifyDataSetChanged mAdapter.notifyDataSetChanged(); mLblArrivalTime.setText(Utils.getTimeFromTimestamp(route.getArrivalTimestamp())); } mLogManager.d(getLogTag(), "Refreshing time UI elements"); Route route = getRoute(); int remainingTime = Utils.getRemainingMinutesToRoute(route); mLblRemainingTime.setText(Utils.getTimeFromTimestamp(remainingTime)); mFirstDrawDone = true; } /** * Returns route data, asking them to the container activity * @return */ private Route getRoute() { Route route = null; if (null != mListener) { // It asks the data to parent activity. Also acceding directly to the model may be a // feasible option. I prefer to see Fragment as strictly correlated to parent // activity route = mListener.getRouteForPosition(mFragmentPos); } else { mLogManager.w(getLogTag(), "It seems that the listener activity is not attached..."); } if (null == route) { throw new IllegalArgumentException("Route cannot be null"); } return route; } private String getLogTag() { return String.format("%s-pos%d", LOG_TAG, mFragmentPos); } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. * <p> * See the Android Training lesson <a href= * "http://developer.android.com/training/basics/fragments/communicating.html" * >Communicating with Other Fragments</a> for more information. */ public interface OnFragmentInteractionListener { public Route getRouteForPosition(int pos); void sendToWear(int fragmentPos); } }