Java tutorial
/* * Copyright 2012 CodeSlap * * 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.jobs.ui.fragment; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListView; import com.actionbarsherlock.app.SherlockFragment; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.codeslap.groundy.Groundy; import com.github.bean.Job; import com.github.jobs.R; import com.github.jobs.adapter.JobsAdapter; import com.github.jobs.bean.SearchPack; import com.github.jobs.loader.JobListLoader; import com.github.jobs.resolver.EmailSubscriberResolver; import com.github.jobs.resolver.SearchJobsResolver; import com.github.jobs.ui.activity.HomeActivity; import com.github.jobs.ui.activity.JobDetailsActivity; import com.github.jobs.ui.dialog.HowToApplyDialog; import com.github.jobs.ui.dialog.SubscribeDialog; import com.github.jobs.utils.ShareHelper; import java.util.ArrayList; import java.util.List; import static com.github.jobs.utils.AnalyticsHelper.*; /** * @author cristian */ public class JobListFragment extends SherlockFragment implements LoaderManager.LoaderCallbacks<List<Job>>, AdapterView.OnItemClickListener, AbsListView.OnScrollListener { private static final String KEY_SEARCH = "search_key"; private static final String KEY_LOADING = "loading_key"; private static final String KEY_LAST_TOTAL_ITEM_COUNT = "last_total_item_count_key"; public static JobListFragment newInstance(SearchPack searchPack) { JobListFragment jobListFragment = new JobListFragment(); Bundle args = new Bundle(); args.putParcelable(KEY_SEARCH, searchPack); jobListFragment.setArguments(args); return jobListFragment; } private static final int JOB_DETAILS = 8474; private static final int HOW_TO_APPLY = 5763; private static final int SHARE = 4722; private SearchPack mCurrentSearch = new SearchPack(); private JobsAdapter mAdapter; private View mMoreRootView; private ListView mList; private boolean mLoading = false; private int mLastTotalItemCount; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mCurrentSearch = (SearchPack) savedInstanceState.getParcelable(KEY_SEARCH); mLoading = savedInstanceState.getBoolean(KEY_LOADING); mLastTotalItemCount = savedInstanceState.getInt(KEY_LAST_TOTAL_ITEM_COUNT); } else { mCurrentSearch = (SearchPack) getArguments().getParcelable(KEY_SEARCH); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.jobs_list, null, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mAdapter = new JobsAdapter(getActivity()); mList = (ListView) getView().findViewById(R.id.job_list); mList.setOnItemClickListener(this); mMoreRootView = getLayoutInflater(savedInstanceState).inflate(R.layout.list_footer, null); mList.addFooterView(mMoreRootView); mList.setAdapter(mAdapter); mList.setOnScrollListener(this); setHasOptionsMenu(true); registerForContextMenu(mList); queryList(); removeFooterFromList(); if (savedInstanceState == null) { triggerJobSearch(); } } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); FragmentActivity activity = getActivity(); if (activity == null || !isAdded()) { return; } AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; Job job = mAdapter.getItem(info.position); menu.setHeaderTitle(job.getTitle()); menu.add(0, JOB_DETAILS, 0, R.string.job_details); menu.add(0, HOW_TO_APPLY, 0, R.string.how_to_apply); menu.add(0, SHARE, 0, R.string.share); getTracker(activity).trackEvent(CATEGORY_JOBS, ACTION_OPEN_CONTEXT, mCurrentSearch.getSearch()); } @Override public boolean onContextItemSelected(android.view.MenuItem item) { FragmentActivity activity = getActivity(); if (activity == null || !isAdded()) { return true; } AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); Job job = mAdapter.getItem(info.position); switch (item.getItemId()) { case JOB_DETAILS: ArrayList<String> ids = mAdapter.getItemsIds(); Intent jobDetailsIntent = new Intent(activity, JobDetailsActivity.class); jobDetailsIntent.putExtra(JobDetailsActivity.EXTRA_CURRENT_JOB_ID, job.getId()); jobDetailsIntent.putExtra(JobDetailsActivity.EXTRA_JOBS_IDS, ids); startActivity(jobDetailsIntent); getTracker(activity).trackEvent(CATEGORY_JOBS, ACTION_FOLLOW_CONTEXT, LABEL_DETAILS); return true; case HOW_TO_APPLY: Intent howToApplyIntent = new Intent(activity, HowToApplyDialog.class); howToApplyIntent.putExtra(HowToApplyDialog.EXTRA_TITLE, job.getTitle()); howToApplyIntent.putExtra(HowToApplyDialog.EXTRA_HOW_TO_APPLY, job.getHowToApply()); startActivity(howToApplyIntent); getTracker(activity).trackEvent(CATEGORY_JOBS, ACTION_FOLLOW_CONTEXT, LABEL_APPLY); return true; case SHARE: startActivity(ShareHelper.getShareIntent(job)); getTracker(activity).trackEvent(CATEGORY_JOBS, ACTION_FOLLOW_CONTEXT, LABEL_SHARE); return true; } return super.onContextItemSelected(item); } @Override public boolean onOptionsItemSelected(MenuItem item) { FragmentActivity activity = getActivity(); if (activity == null || !isAdded()) { return true; } switch (item.getItemId()) { case R.id.menu_subscribe: Intent subscribeIntent = new Intent(activity, SubscribeDialog.class); subscribeIntent.putExtra(EmailSubscriberResolver.EXTRA_SEARCH, mCurrentSearch); startActivity(subscribeIntent); getTracker(activity).trackEvent(CATEGORY_SUBSCRIBE, ACTION_OPEN, LABEL_DIALOG); break; case R.id.menu_delete: ((HomeActivity) activity).removeSearch(mCurrentSearch); getTracker(activity).trackEvent(CATEGORY_SEARCH, ACTION_REMOVE, mCurrentSearch.getSearch()); break; } return super.onOptionsItemSelected(item); } @Override public Loader<List<Job>> onCreateLoader(int id, Bundle args) { FragmentActivity activity = getActivity(); if (activity == null || !isAdded()) { return null; } return new JobListLoader(activity, mCurrentSearch); } @Override public void onLoadFinished(Loader<List<Job>> listLoader, List<Job> data) { mAdapter.updateItems(data); if (data.isEmpty()) { removeFooterFromList(); } } @Override public void onLoaderReset(Loader<List<Job>> listLoader) { mAdapter.clear(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mAdapter.getCount() <= position) { // ignore invalid clicks return; } Job job = mAdapter.getItem(position); ArrayList<String> ids = mAdapter.getItemsIds(); Intent intent = new Intent(getActivity(), JobDetailsActivity.class); intent.putExtra(JobDetailsActivity.EXTRA_CURRENT_JOB_ID, job.getId()); intent.putExtra(JobDetailsActivity.EXTRA_JOBS_IDS, ids); startActivity(intent); getTracker(getActivity()).trackEvent(CATEGORY_JOBS, ACTION_OPEN, job.getTitle() + "," + job.getUrl()); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (mMoreRootView == null) { return; } if (totalItemCount <= 1) { return; } totalItemCount -= mList.getHeaderViewsCount(); if (!mLoading && mLastTotalItemCount != totalItemCount && (totalItemCount - visibleItemCount) == firstVisibleItem) { mLoading = true; mLastTotalItemCount = totalItemCount; loadMore(); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); if (menu.findItem(R.id.menu_subscribe) == null && !mCurrentSearch.isDefault()) { inflater.inflate(R.menu.jobs_list_menu, menu); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_SEARCH, mCurrentSearch); outState.putBoolean(KEY_LOADING, mLoading); outState.putInt(KEY_LAST_TOTAL_ITEM_COUNT, mLastTotalItemCount); } private void queryList() { try { FragmentActivity activity = getActivity(); if (activity == null || !isAdded()) { return; } LoaderManager loaderManager = activity.getSupportLoaderManager(); Loader<Object> loader = loaderManager.getLoader(mCurrentSearch.hashCode()); if (loader == null) { loaderManager.initLoader(mCurrentSearch.hashCode(), null, this); } else { loaderManager.restartLoader(mCurrentSearch.hashCode(), null, this); } } catch (IllegalStateException e) { // happens when activity is closed. We can't use isResumed since it will be false when the activity is // not being shown, thus it will cause problems if user loads another screen while this is still loading } } private void removeFooterFromList() { if (mMoreRootView == null) { return; } mList.removeFooterView(mMoreRootView); mMoreRootView = null; } private void addFooterToList() { if (mMoreRootView == null) { Context activity = getActivity(); if (activity == null || !isAdded()) { return; } mMoreRootView = LayoutInflater.from(activity).inflate(R.layout.list_footer, null); mList.addFooterView(mMoreRootView); } else if (mList.getFooterViewsCount() == 0) { mList.addFooterView(mMoreRootView); } } private void loadMore() { mCurrentSearch.setPage(mCurrentSearch.getPage() + 1); triggerJobSearch(); } private void triggerJobSearch() { Bundle extras = new Bundle(); extras.putParcelable(SearchJobsResolver.EXTRA_SEARCH_PACK, mCurrentSearch); mLoading = true; HomeActivity activity = (HomeActivity) getActivity(); if (activity == null || !isAdded()) { return; } SearchReceiverFragment receiver = activity.getSearchReceiver(); Groundy.execute(getActivity(), SearchJobsResolver.class, receiver.getReceiver(), extras); ((SherlockFragmentActivity) getActivity()).setSupportProgressBarIndeterminateVisibility(true); } public void onFinished(Bundle resultData) { ArrayList<Parcelable> parcelableArrayList = resultData.getParcelableArrayList(SearchJobsResolver.DATA_JOBS); if (parcelableArrayList == null) { return; } ArrayList<Job> jobs = new ArrayList<Job>(); for (Parcelable parcelable : parcelableArrayList) { jobs.add((Job) parcelable); } mAdapter.addItems(jobs); if (jobs.size() == 0) { removeFooterFromList(); } else { addFooterToList(); } mLoading = false; } public void onError() { removeFooterFromList(); mLoading = false; } public void onProgressChanged(boolean running) { mLoading = running; } }