Java tutorial
/* * Copyright (C) 2016 sin3hz * * 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 io.github.sin3hz.fastjumper.sample; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; import java.util.Collections; import java.util.List; import io.github.sin3hz.fastjumper.FastJumper; import io.github.sin3hz.fastjumper.callback.LinearScrollCalculator; import io.github.sin3hz.fastjumper.callback.SpannableCallback; import io.github.sin3hz.fastjumper.sample.utils.AlphabeticIndexCompat; import io.github.sin3hz.fastjumper.sample.utils.DividerItemDecoration; public class AppListFragment extends Fragment implements MainActivity.Listener { private static final String TAG = AppListFragment.class.getSimpleName(); private static final int LOADER_PHOTO = 1; public static AppListFragment newInstance() { AppListFragment fragment = new AppListFragment(); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } private View mEmptyView; private View mContentView; private RecyclerView mRecyclerView; private SwipeRefreshLayout mSwipeRefreshLayout; private AppListAdapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; private FastJumper mFastJumper; private SpannableCallback mJumperCallback; private FloatingActionButton mFab; private DividerItemDecoration mDividerDecoration; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_app_list, container, false); mEmptyView = view.findViewById(R.id.empty); mContentView = view.findViewById(R.id.content); mRecyclerView = (RecyclerView) view.findViewById(R.id.list); mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe); mFab = (FloatingActionButton) getActivity().findViewById(R.id.fab); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { getLoaderManager().restartLoader(0, null, mLoaderCallbacks); } }); mAdapter = new AppListAdapter(); mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mLayoutManager = new LinearLayoutManager(getContext()); mRecyclerView.setAdapter(mAdapter); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setHasFixedSize(true); mDividerDecoration = new DividerItemDecoration(getContext()); setupFastJumper(); } private void setupFastJumper() { mJumperCallback = new SpannableCallback() { @Override public boolean isSectionEnable() { return true; } @Override public String getSection(int position) { return mAdapter.getSection(position); } }; mJumperCallback.setScrollCalculator(new LinearScrollCalculator(mRecyclerView) { @Override public int getItemHeight(int position) { return mAdapter.getItemHeight(position); } }); mFastJumper = new FastJumper(mJumperCallback); //mFastJumper = new FastJumper(new SimpleCallback()); mFastJumper.attachToRecyclerView(mRecyclerView); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getLoaderManager().initLoader(LOADER_PHOTO, null, mLoaderCallbacks); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.menu_app_list, menu); } private boolean mUseDivider; private boolean mLoadMore; @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); menu.findItem(R.id.action_use_divider).setChecked(mUseDivider); menu.findItem(R.id.action_load_more).setChecked(mLoadMore); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_use_divider: { mUseDivider = !item.isChecked(); item.setChecked(mUseDivider); setupDivider(); return true; } case R.id.action_load_more: { mLoadMore = !item.isChecked(); return true; } default: return super.onOptionsItemSelected(item); } } private void setupDivider() { if (mUseDivider) { mRecyclerView.addItemDecoration(mDividerDecoration, 0); } else { mRecyclerView.removeItemDecoration(mDividerDecoration); } // Item height changed, invalidate ScrollerCalculator to clear its cache. mJumperCallback.getScrollCalculator().invalidateCache(); // Invalidate FastJumper to update scroller's position. mFastJumper.invalidate(); } private LoaderManager.LoaderCallbacks<List<AppInfo>> mLoaderCallbacks = new LoaderManager.LoaderCallbacks<List<AppInfo>>() { @Override public Loader<List<AppInfo>> onCreateLoader(int id, Bundle args) { return new AppLoader(getContext()); } @Override public void onLoadFinished(Loader<List<AppInfo>> loader, final List<AppInfo> data) { mSwipeRefreshLayout.setRefreshing(false); //mAppInfoList.clear(); mAppInfoList.addAll(data); mAdapter.notifyDataSetChanged(); if (data.size() == 0) { showEmptyView(); } else { showContentView(); } } @Override public void onLoaderReset(Loader<List<AppInfo>> loader) { } }; private List<AppInfo> mAppInfoList = new ArrayList<>(); private static class AppInfo implements Comparable<AppInfo> { String name; Drawable icon; String section; public AppInfo() { } @Override public int compareTo(@NonNull AppInfo another) { return this.section.compareTo(another.section); } } private static class AppLoader extends AsyncTaskLoader<List<AppInfo>> { private AlphabeticIndexCompat mIndexer; private final PackageManager mPackageManager; private List<AppInfo> mApps; public AppLoader(Context context) { super(context); mPackageManager = getContext().getPackageManager(); mIndexer = new AlphabeticIndexCompat(context); } @Override public List<AppInfo> loadInBackground() { List<ApplicationInfo> apps = mPackageManager.getInstalledApplications(0); if (apps == null) { apps = new ArrayList<>(); } List<AppInfo> appInfos = new ArrayList<>(apps.size()); for (int i = 0; i < apps.size(); i++) { AppInfo appInfo = new AppInfo(); appInfo.icon = apps.get(i).loadIcon(mPackageManager); appInfo.name = apps.get(i).loadLabel(mPackageManager).toString(); appInfo.section = mIndexer.computeSectionName(appInfo.name); appInfos.add(appInfo); } Collections.sort(appInfos); return appInfos; } @Override public void deliverResult(List<AppInfo> apps) { if (isReset()) { if (apps != null) { releaseResources(apps); return; } } List<AppInfo> oldApps = mApps; mApps = apps; if (isStarted()) { super.deliverResult(apps); } if (oldApps != null && oldApps != apps) { releaseResources(oldApps); } } @Override protected void onStartLoading() { if (mApps != null) { deliverResult(mApps); } if (takeContentChanged()) { forceLoad(); } else if (mApps == null) { forceLoad(); } } @Override protected void onStopLoading() { cancelLoad(); } @Override protected void onReset() { onStopLoading(); if (mApps != null) { releaseResources(mApps); mApps = null; } } @Override public void onCanceled(List<AppInfo> apps) { super.onCanceled(apps); releaseResources(apps); } @Override public void forceLoad() { super.forceLoad(); } private void releaseResources(List<AppInfo> apps) { } } private class AppListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private int mItemHeight = getResources().getDimensionPixelSize(R.dimen.app_item_height); class ViewHolder extends RecyclerView.ViewHolder { ImageView icon; TextView title; TextView subtitle; public ViewHolder(View itemView) { super(itemView); icon = (ImageView) itemView.findViewById(R.id.icon); title = (TextView) itemView.findViewById(R.id.text_title); subtitle = (TextView) itemView.findViewById(R.id.text_subtitle); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { final ViewHolder vh = (ViewHolder) holder; AppInfo appInfo = getItem(position); vh.title.setText(appInfo.name); vh.icon.setImageDrawable(appInfo.icon); vh.subtitle.setText(getIndexSection(holder.getAdapterPosition())); vh.subtitle.setVisibility(View.GONE); if (mLoadMore && holder.getAdapterPosition() == mAppInfoList.size() - 1) { getLoaderManager().restartLoader(LOADER_PHOTO, null, mLoaderCallbacks); } } @Override public int getItemCount() { return mAppInfoList.size(); } public AppInfo getItem(int position) { return mAppInfoList.get(position); } public int getItemHeight(int position) { return mItemHeight + (mUseDivider ? mDividerDecoration.getDividerHeight() : 0); } public String getSection(int position) { return getAlphabetSection(position); } public String getAlphabetSection(int position) { return getItem(position).section; } public String getIndexSection(int position) { return "#" + position; } } private void showContentView() { mContentView.setVisibility(View.VISIBLE); mEmptyView.setVisibility(View.GONE); } private void showEmptyView() { mContentView.setVisibility(View.GONE); mEmptyView.setVisibility(View.VISIBLE); } @Override public void onAppBarCollapse(boolean isCollapsed) { mSwipeRefreshLayout.setEnabled(!isCollapsed); } @Override public void onPageScrolling(boolean scrolling) { if (scrolling) { mFastJumper.hide(); } } @Override public void onScrollToTop() { mRecyclerView.smoothScrollToPosition(0); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if (isVisibleToUser && mFab != null) { mFab.hide(); } } }