I'm developing an android kind-of-gallery-app with Firebase, so I will have plenty of images. I know that I need to be careful about memory management.
When I was searching how to find memory leak in android apps, I came across with LeakCanary. It looks really great, so I used in my app.
Basically my app has 3 fragments, which are Drawer, ProductGrid and ProductDetail. Sometimes LeakCanary says that I have a memory leak in ProductGrid, but I couldn't find it! Usually, adapters or static methods or listeners could cause memory leak because of Context object, but my knowledge is not sufficient to say 'aah that's because of here'
Here are the classes. Where is the leak?(If you suggest me anything that I can improve my code or approach, I would be appreciated!)
Because of body character limit, I put the link leak canary log file.
How I suspect there is a memory leak
First of all, LeakCanary shows a dialog and logs the dump. Second thing is, when I click on an item in drawer, in grid and in detail like 15 times(respectively), memory usage increases. It starts with 18M, increases 22M-23M after showing 3 images(normal). Then it heads up to 29M-30M after clicking on 15 times. If you click on around 30-40, memory usage increases 34M-35M
Edit: I've just figured out that, if I open and close drawer, memory usage increases 0.05M everytime, so one time opening and closing drawer costs 0.1M! What am i missing?
Main.java
public class Main extends ActionBarActivity implements DrawerListener {
private Toolbar mToolbar;
private Drawer drawerFragment;
private HomePage homeFragment;
private FragmentHelper fh = new FragmentHelper();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (homeFragment == null)
homeFragment = new HomePage();
if (savedInstanceState == null) {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
drawerFragment = (Drawer)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
drawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout), mToolbar);
drawerFragment.setDrawerListener(this);
drawerFragment.setRetainInstance(true);
displayView(null);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_home) {
getSupportActionBar().setTitle(getString(R.string.app_name));
fh.replace(getSupportFragmentManager(), homeFragment, R.id.container_body);
return true;
}
if (id == R.id.action_settings) {
return true;
}
if (id == R.id.action_search) {
Toast.makeText(getApplicationContext(), "Search action is selected!", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onDrawerItemSelected(View view, int position, Category category) {
displayView(category);
}
private void displayView(Category category) {
if (category != null) {
getSupportActionBar().setTitle(category.getName());
ProductGrid gridFragment = new ProductGrid();
Bundle args = new Bundle();
args.putString(Product.CATEGORY_ID, category.getId());
gridFragment.setArguments(args);
fh.replace(getSupportFragmentManager(), gridFragment, R.id.container_body);
} else {
getSupportActionBar().setTitle(getString(R.string.app_name));
fh.replace(getSupportFragmentManager(), homeFragment, R.id.container_body);
}
}
}
Drawer.java
public class Drawer extends Fragment {
private Firebase mFirebase;
private Alert alert;
private RecyclerView recyclerView;
private View containerView;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerListener drawerListener;
private DrawerAdapter mAdapter;
private List<Category> mCategories;
public Drawer() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
alert = new Alert(getActivity().getApplicationContext());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.drawer, container, false);
mCategories = new ArrayList<>();
mAdapter = new DrawerAdapter(mCategories);
recyclerView = (RecyclerView) layout.findViewById(R.id.drawer_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
recyclerView.setItemAnimator(new SlideInOutLeftItemAnimator(recyclerView));
recyclerView.setAdapter(mAdapter);
mFirebase = new Firebase(getActivity().getResources().getString(R.string.firebase_ref))
.child(FirebaseRoots.CATEGORY);
Query query = mFirebase.orderByChild(Category.PRIO);
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Category model = dataSnapshot.getValue(Category.class);
model.setId(dataSnapshot.getKey());
mCategories.add(model);
recyclerView.scrollToPosition(mCategories.size() - 1);
mAdapter.notifyItemInserted(mCategories.size() - 1);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Category model = dataSnapshot.getValue(Category.class);
model.setId(dataSnapshot.getKey());
int index = -1;
for (int i = 0; i < mCategories.size(); i++) {
if (mCategories.get(i).getId().equals(model.getId())) {
index = i;
break;
}
}
mCategories.set(index, model);
recyclerView.scrollToPosition(0);
mAdapter.notifyItemChanged(index);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Category model = dataSnapshot.getValue(Category.class);
model.setId(dataSnapshot.getKey());
int index = -1;
for (int i = 0; i < mCategories.size(); i++) {
if (mCategories.get(i).getId().equals(model.getId())) {
index = i;
break;
}
}
mCategories.remove(index);
recyclerView.scrollToPosition(0);
mAdapter.notifyItemRemoved(index);
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
alert.show(firebaseError.toString());
}
});
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity().getApplicationContext(),
recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
Category category = mCategories.get(position);
drawerListener.onDrawerItemSelected(view, position, category);
mDrawerLayout.closeDrawer(containerView);
}
#Override
public void onLongClick(View view, int position) {
}
}));
return layout;
}
public void setUp(int fragmentId, DrawerLayout drawerLayout, final Toolbar toolbar) {
containerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActivity().invalidateOptionsMenu();
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
getActivity().invalidateOptionsMenu();
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
toolbar.setAlpha(1 - slideOffset / 2);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mDrawerToggle.syncState();
}
});
}
public void setDrawerListener(DrawerListener listener) {
this.drawerListener = listener;
}
}
ProductGrid.java
public class ProductGrid extends Fragment implements ChildEventListener{
private Firebase mFirebaseRef;
private Alert alert;
private RecyclerView recyclerView;
private GridAdapter mAdapter;
private String categoryId;
private ArrayList<Product> mProducts;
private FileSystem fs;
public ProductGrid() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.categoryId = getArguments().getString(Product.CATEGORY_ID);
this.alert = new Alert(getActivity().getApplicationContext());
this.fs = new FileSystem(getActivity().getApplicationContext());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.grid, container, false);
fieldInitialize(layout);
mProducts = new ArrayList<>();
mAdapter = new GridAdapter(mProducts, getActivity().getApplicationContext());
recyclerView.addItemDecoration(new MarginDecoration(getActivity()));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
recyclerView.setAdapter(mAdapter);
mFirebaseRef = new Firebase(getActivity().getResources().getString(R.string.firebase_ref))
.child(FirebaseRoots.PRODUCT);
Query query = mFirebaseRef.orderByChild(Product.CATEGORY_ID).equalTo(categoryId);
query.addChildEventListener(this);
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
#Override
public void onClick(View view, int position) {
ProductDetail detailFragment = new ProductDetail();
Bundle args = new Bundle();
args.putSerializable("product", mProducts);
args.putInt("position", position);
detailFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, detailFragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onLongClick(View view, int position) {
}
}));
return layout;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onDetach() {
super.onDetach();
}
public void fieldInitialize(View layout) {
recyclerView = (RecyclerView) layout.findViewById(R.id.product_grid_layout);
}
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Product model = dataSnapshot.getValue(Product.class);
model.setId(dataSnapshot.getKey());
mProducts.add(model);
if (!fs.getFileNames().contains(model.getName() + FileExt.JPG.get())) {
fs.writeImage(model.getName(), ImageUtil.base64ToBitmap(
StringUtil.getBase64FromUrl(model.getImageData().getDataUrl())));
}
Collections.sort(mProducts);
recyclerView.scrollToPosition(0);
mAdapter.notifyItemInserted(mProducts.size() - 1);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Product model = dataSnapshot.getValue(Product.class);
model.setId(dataSnapshot.getKey());
fs.writeImage(model.getName(), ImageUtil.base64ToBitmap(
StringUtil.getBase64FromUrl(model.getImageData().getDataUrl())));
int index = -1;
for (int i = 0; i < mProducts.size(); i++) {
if (mProducts.get(i).getId().equals(model.getId())) {
index = i;
break;
}
}
mProducts.set(index, model);
recyclerView.scrollToPosition(0);
mAdapter.notifyItemChanged(index);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Product model = dataSnapshot.getValue(Product.class);
model.setId(dataSnapshot.getKey());
fs.deleteImage(model.getName());
int index = -1;
for (int i = 0; i < mProducts.size(); i++) {
if (mProducts.get(i).getId().equals(model.getId())) {
index = i;
break;
}
}
mProducts.remove(index);
recyclerView.scrollToPosition(0);
mAdapter.notifyItemRemoved(index);
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
alert.show(firebaseError.toString());
}
#Override public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = AcarsanApp.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
ProductDetail.java
public class ProductDetail extends Fragment {
private FullScreenImageAdapter adapter;
private ViewPager viewPager;
private ArrayList<Product> products;
private int position;
public ProductDetail() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
products = (ArrayList<Product>) getArguments().getSerializable("product");
position = getArguments().getInt("position");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.product_detail, container, false);
viewPager = (ViewPager) view.findViewById(R.id.product_gallery);
adapter = new FullScreenImageAdapter(getActivity().getApplicationContext(), products);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(position);
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onDetach() {
super.onDetach();
}
}
FileSystem
public class FileSystem {
private Context mContext;
public static final String PHOTOS_FOLDER = "photos";
public FileSystem(Context mContext) {
this.mContext = mContext;
}
public void writeImage(String name, Bitmap bitmap) {
String filename = name + FileExt.JPG.get();
File dir = mContext.getDir(PHOTOS_FOLDER, Context.MODE_PRIVATE);
File fileWithinDir = new File(dir, filename);
FileOutputStream outputStream;
try {
outputStream = new FileOutputStream(fileWithinDir);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public List<String> getFileNames() {
List<String> fileNames = new ArrayList<>();
File file = mContext.getDir(PHOTOS_FOLDER, Context.MODE_PRIVATE);
File[] files = file.listFiles();
for (File f : files) {
fileNames.add(f.getName());
}
return fileNames;
}
}
ImageUtil
public class ImageUtil {
public static Bitmap base64ToBitmap(String encodedImage) {
if (encodedImage == null)
return null;
byte[] decodedString = Base64.decode(encodedImage, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
}
}
Related
I am trying to create an intent with bundle extras but I am getting null pointer exception error on the Array List.
Here is the error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.ArrayList android.os.Bundle.getParcelableArrayList(java.lang.String)' on a null object reference
Am I implementing intents wrong?
Here is my application below for MP3 Player:
PlaylistSelector:
public class PlaylistSelector extends AppCompatActivity {
ListView listview;
String[] items;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.playlist);
listview = findViewById(R.id.listViewSong);
runtimePermission();
}
public void runtimePermission()
{
Dexter.withContext(this).withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) {
displaySongs();
}
#Override
public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) {
}
#Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
}
public ArrayList<File> findSong (File file)
{
ArrayList<File> arrayList = new ArrayList<>();
File[] files = file.listFiles();
for (File singlefile: files)
{
if (singlefile.isDirectory() && !singlefile.isHidden())
{
arrayList.addAll(findSong(singlefile));
}
else
{
if (singlefile.getName().endsWith(".mp3") || singlefile.getName().endsWith(".wav"))
{
arrayList.add(singlefile);
}
}
}
return arrayList;
}
void displaySongs()
{
final ArrayList<File> mySongs = findSong(Environment.getExternalStorageDirectory());
items = new String[mySongs.size()];
for(int i = 0; i<mySongs.size(); i++)
{
items[i] = mySongs.get(i).getName().toString().replace(".mp3","").replace(".wav","");
}
/*ArrayAdapter<String> myAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,songs);
listview.setAdapter(myAdapter);*/
customAdapter customAdapter = new customAdapter();
listview.setAdapter(customAdapter);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String songName = (String) listview.getItemAtPosition(i);
startActivity(new Intent(getApplicationContext(), MainActivity.class)
.putExtra("songs", mySongs)
.putExtra("songname", songName)
.putExtra("pos", i));
}
});
}
class customAdapter extends BaseAdapter{
#Override
public int getCount() {
return items.length;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View myView = getLayoutInflater().inflate(R.layout.list_item, null);
TextView textsong = myView.findViewById(R.id.txtsongname);
textsong.setSelected(true);
textsong.setText(items[i]);
return myView;
}
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private InputSource inputSource;
Button playbtn, btnnext,btnprev,btnff,btnrw;
TextView txtsn, txtsstop,txtsstart;
SeekBar seekmusic;
BarVisualizer visualizer;
String sname;
public static final String EXTRA_NAME = "song_name";
static MediaPlayer mediaPlayer;
int position;
ArrayList<File> mySongs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View frameLayoutMP = findViewById(R.id.preview_mp3_layout);
btnprev = findViewById(R.id.btnprev);
playbtn = findViewById(R.id.playbtn);
btnnext = findViewById(R.id.btnnext);
btnrw = findViewById(R.id.btnrw);
btnff = findViewById(R.id.btnff);
txtsn = findViewById(R.id.txtsn);
txtsstop = findViewById(R.id.txtsstop);
txtsstart = findViewById(R.id.txtsstart);
seekmusic = findViewById(R.id.seekbar);
visualizer = findViewById(R.id.blast);
if (mediaPlayer != null)
{
mediaPlayer.stop();
mediaPlayer.release();
}
Intent i = getIntent();
Bundle bundle = i.getExtras();
mySongs = (ArrayList) bundle.getParcelableArrayList("songs");
String songName = i.getStringExtra("songname");
position = bundle.getInt("pos",0);
txtsn.setSelected(true);
Uri uri = Uri.parse(mySongs.get(position).toString());
sname = mySongs.get(position).getName();
txtsn.setText(sname);
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
mediaPlayer.start();
playbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(mediaPlayer.isPlaying())
{
playbtn.setBackgroundResource(R.drawable.ic_play);
mediaPlayer.pause();
}
else
{
playbtn.setBackgroundResource(R.drawable.ic_pause);
mediaPlayer.start();
}
}
});
}
}
I am trying to get this intent to grab song lists from playlists and put it into the player
I have been trying to implement search using firestoreUI but when i run my code the logcat says that:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.firebase.ui.firestore.FirestoreRecyclerAdapter.startListening()' on a null object reference
at com.example.homebarberv1.Search.onStart(Search.java:93)
below is my code:
public class Search extends AppCompatActivity implements FirebaseAuth.AuthStateListener{
private EditText searchField;
private Button searchButton;
private RecyclerView searchRecyclerview;
private FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
private FirestoreRecyclerAdapter<User, UsersViewHolder> adapter;
private String searchText;
static {
FirebaseFirestore.setLoggingEnabled(true);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_search);
searchField = findViewById(R.id.SearchField);
searchButton = findViewById(R.id.SearchButton);
searchRecyclerview = findViewById(R.id.SearchContainer);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setReverseLayout(true);
manager.setStackFromEnd(true);
searchRecyclerview .setHasFixedSize(true);
searchRecyclerview .setLayoutManager(manager);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setSelectedItemId(R.id.search);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.search:
return true;
case R.id.appointment:
startActivity(new Intent(getApplicationContext(),HomePage.class));
overridePendingTransition(0,0);
return true;
case R.id.profile:
startActivity(new Intent(getApplicationContext(),Profile.class));
overridePendingTransition(0,0);
return true;
}
return false;
}
});
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
searchText = searchField.getText().toString();
firebaseUserSearch(searchText);
}
});
}
#Override
public void onStart() {
super.onStart();
if (isSignedIn()) {
adapter.startListening();
}
firebaseAuth.addAuthStateListener(this);
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
FirebaseAuth.getInstance().removeAuthStateListener(this);
}
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth auth) {
if (isSignedIn()) {
adapter.startListening();
} else {
Toast.makeText(Search.this,"user are not signed in",Toast.LENGTH_LONG);
}
}
private boolean isSignedIn() {
return FirebaseAuth.getInstance().getCurrentUser() != null;
}
#NonNull
private void firebaseUserSearch(String searchText){
CollectionReference sCollection =
FirebaseFirestore.getInstance().collection("Barbers");
Query sQuery = sCollection.startAt(searchText).endAt(searchText + "\uf8ff");
FirestoreRecyclerOptions<User> options =
new FirestoreRecyclerOptions.Builder<User>()
.setQuery(sQuery, User.class)
.setLifecycleOwner(this)
.build();
adapter = new FirestoreRecyclerAdapter<User, UsersViewHolder>(options) {
#NonNull
#Override
public UsersViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.searchlist, parent, false);
return new UsersViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull UsersViewHolder holder, int position, #NonNull User model) {
holder.setName(model.getShopname());
holder.setPic(model.getPiclink());
holder.setAddress(model.getAddress() + ", " + model.getPostcode().toString() + ", " + model.getCity());
}
};
searchRecyclerview.setAdapter(adapter);
}
public class UsersViewHolder extends RecyclerView.ViewHolder {
private View mView;
public UsersViewHolder(View itemView) {
super(itemView);
mView = itemView;
}
public void setName(String name){
TextView userNameView = (TextView) mView.findViewById(R.id.shopNameS);
userNameView.setText(name);
}
public void setPic(String link){
ImageView imageView = (ImageView)mView.findViewById(R.id.imageS);
Picasso.get().load(link).into(imageView);
}
public void setAddress(String address){
TextView addressView = (TextView) mView.findViewById(R.id.shopAddressS);
addressView.setText(address);
}
}
}
the error refers to this line:
adapter.startListening();
I'm still new to Android, so I do not really understand what I'm doing wrong here, help is really appreciated
You need to ensure that adapter has been given a value, before you call adapter.startListening on it.
That means that in onStart you need to ensure the adapter exists:
#Override
public void onStart() {
super.onStart();
if (isSignedIn() && adapter != null) {
adapter.startListening();
}
firebaseAuth.addAuthStateListener(this);
}
And then also start listening on the adapter when you create it and the user is signed in. So:
adapter = new FirestoreRecyclerAdapter<User, UsersViewHolder>(options) {
...
});
if (isSignedIn()) {
adapter.startListening();
}
I am trying to make an app that teaches C Language. My app has 4 fragments, "Learning" "Quizzes" "Ranking" and "Profile".
My lesson cards is in "Learning" fragment, when you first sign in to app, Lesson 1 is available and the others are locked. What I'm trying to do is when you completed Lesson 1, remove the lock on Lesson 2. My code works when debugging but on run, i have to click one more time to "Learning" fragment on my BottomNavigation. I mean the "Learn" item on the Bottom Navigation, you can see it in the screenshots.
This is what it looks like in the beginning
And this is after completing Lesson 1
I'm not getting any erros, as I said my code works well but I just need to click twice.
What I've Tried
I couldn't find much to do, so i didn't try because i'm also kinda new at android programming, so please be specific.
My Class That I am Filling The Learn Fragment
public class Learning extends Fragment {
RecyclerView recyclerView;
FirebaseRecyclerAdapter<LearningHelperClass, LearningViewHolder> recyclerAdapter;
RecyclerView.LayoutManager layoutManager;
FirebaseDatabase database;
DatabaseReference databaseReference;
DatabaseReference lessons,user;
public int index;
public UserHelperClass current;
public static Learning newInstance(){
Learning learning = new Learning();
return learning;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_learning, container, false);
recyclerView = (RecyclerView)view.findViewById(R.id.recyclerViewLearning);
recyclerView.setHasFixedSize(true);
layoutManager = new GridLayoutManager(container.getContext(),1);
recyclerView.setLayoutManager(layoutManager);
user.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
current = dataSnapshot.child(Common.currentUser.getUsername()).getValue(UserHelperClass.class);
Common.currentUser = current;
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}); //currentUser update
loadData();
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = FirebaseDatabase.getInstance();
databaseReference = database.getReference("Lessons");
lessons = database.getReference("LessonInside");
user = database.getReference("users");
}
private void loadData() {
FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder<LearningHelperClass>()
.setQuery(databaseReference, LearningHelperClass.class)
.build();
recyclerAdapter = new FirebaseRecyclerAdapter<LearningHelperClass, LearningViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull LearningViewHolder learningViewHolder, int i, #NonNull LearningHelperClass learningHelperClass) {
index = i;
learningViewHolder.Name.setText(learningHelperClass.getName());
learningViewHolder.Number.setText(learningHelperClass.getNumber());
if(Common.currentUser.getCmpLesson().equals("") && index == 0) {
learningViewHolder.itemView.setEnabled(true);
learningViewHolder.Lock.setVisibility(View.INVISIBLE);
learningViewHolder.Tick.setVisibility(View.INVISIBLE);
} else if (Common.currentUser.getCmpLesson().equals("") && index != 0){
learningViewHolder.Lock.setVisibility(View.VISIBLE);
learningViewHolder.Tick.setVisibility(View.INVISIBLE);
learningViewHolder.itemView.setEnabled(false);
}else if (Common.currentUser.getCmpLesson().contains(controlTick())) {
learningViewHolder.Tick.setVisibility(View.VISIBLE);
learningViewHolder.Lock.setVisibility(View.INVISIBLE);
learningViewHolder.itemView.setEnabled(true);
}else if (Common.currentUser.getCmpLesson().contains(controlLock())){
learningViewHolder.Tick.setVisibility(View.INVISIBLE);
learningViewHolder.Lock.setVisibility(View.INVISIBLE);
learningViewHolder.itemView.setEnabled(true);
} else {
learningViewHolder.Lock.setVisibility(View.VISIBLE);
learningViewHolder.Tick.setVisibility(View.INVISIBLE);
learningViewHolder.itemView.setEnabled(false);
}
learningViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity().getApplicationContext(), StartLesson.class);
intent.putExtra("Name", learningHelperClass.getName());
Common.lessonId = recyclerAdapter.getRef(i).getKey();
startActivity(intent);
}
});
}
#NonNull
#Override
public LearningViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_view,parent,false);
return new LearningViewHolder(view);
}
};
recyclerAdapter.notifyDataSetChanged();
recyclerAdapter.startListening();
recyclerView.setAdapter(recyclerAdapter);
}
public String controlTick(){
if (index >= 9){
return " "+(index+1)+" ";
}else
return " 0"+(index+1)+" ";
}
public String controlLock(){
if (index >= 9){
return " "+(index)+" ";
}else
return " 0"+(index)+" ";
}}
My Test Activity Class That Automatically Starts When You Finish a Lesson, It also Updates the Firebase about a User Finished the Lesson
public class Tests extends AppCompatActivity implements View.OnClickListener {
ImageView question_image;
Button btnA,btnB,btnC,btnD,btnNext;
TextView txtQuestionNum,question_text;
public String addComplete;
FirebaseDatabase database;
DatabaseReference user;
int index=0,thisQuestion=0,totalQuestion,correctAnswer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_tests);
txtQuestionNum = (TextView)findViewById(R.id.txtTotalQuestionTest);
question_text = (TextView)findViewById(R.id.quest_textTest);
question_image = (ImageView)findViewById(R.id.quest_imageTest);
btnA = (Button)findViewById(R.id.btnAnswerATest);
btnB = (Button)findViewById(R.id.btnAnswerBTest);
btnC = (Button)findViewById(R.id.btnAnswerCTest);
btnD = (Button)findViewById(R.id.btnAnswerDTest);
btnNext = (Button)findViewById(R.id.nextButtonTest);
addComplete = Common.lessonId;
database = FirebaseDatabase.getInstance();
user = database.getReference("users");
btnA.setOnClickListener(this);
btnB.setOnClickListener(this);
btnC.setOnClickListener(this);
btnD.setOnClickListener(this);
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
btnA.setClickable(true);
btnB.setClickable(true);
btnC.setClickable(true);
btnD.setClickable(true);
btnA.setBackgroundColor(Color.WHITE);
btnB.setBackgroundColor(Color.WHITE);
btnC.setBackgroundColor(Color.WHITE);
btnD.setBackgroundColor(Color.WHITE);
showQuestion(++index);
if (index+1 == totalQuestion) {
btnNext.setText("Finish Course");
user.child(Common.currentUser.getUsername()).child("cmpLesson").setValue(Common.currentUser.getCmpLesson()+" "+addComplete+" ");
}
}
});
}
#Override
public void onClick(View v) {
if (index < totalQuestion) {
Button clickedButton = (Button)v;
btnA.setClickable(false);
btnB.setClickable(false);
btnC.setClickable(false);
btnD.setClickable(false);
if (clickedButton.getText().equals(Common.questionList.get(index).getCorrectAnswer()))
{
clickedButton.setBackgroundColor(Color.GREEN);
correctAnswer++;
} else {
clickedButton.setBackgroundColor(Color.RED);
if (btnA.getText().equals(Common.questionList.get(index).getCorrectAnswer()))
btnA.setBackgroundColor(Color.GREEN);
if (btnB.getText().equals(Common.questionList.get(index).getCorrectAnswer()))
btnB.setBackgroundColor(Color.GREEN);
if (btnC.getText().equals(Common.questionList.get(index).getCorrectAnswer()))
btnC.setBackgroundColor(Color.GREEN);
if (btnD.getText().equals(Common.questionList.get(index).getCorrectAnswer()))
btnD.setBackgroundColor(Color.GREEN);
}
}
}
private void showQuestion(int index) {
if (index < totalQuestion) {
thisQuestion++;
txtQuestionNum.setText(String.format("%d / %d", thisQuestion, totalQuestion));
if(Common.questionList.get(index).getIsImageQuestion().equals("true"))
{
Picasso.get().load(Common.questionList.get(index).getQuestion())
.into(question_image);
question_image.setVisibility(View.VISIBLE);
question_text.setVisibility(View.INVISIBLE);
}
else
{
question_text.setText(Common.questionList.get(index).getQuestion());
question_image.setVisibility(View.INVISIBLE);
question_text.setVisibility(View.VISIBLE);
}
btnA.setText(Common.questionList.get(index).getAnswerA());
btnB.setText(Common.questionList.get(index).getAnswerB());
btnC.setText(Common.questionList.get(index).getAnswerC());
btnD.setText(Common.questionList.get(index).getAnswerD());
} else
{
//Son Soru
Intent intent = new Intent(this, HomeNavigationBottom.class);
startActivity(intent);
finish();
}
}
#Override
protected void onResume() {
super.onResume();
totalQuestion = Common.questionList.size();
showQuestion(index);
}}
My UserHelperClass
public class UserHelperClass {
String username,email,password,cmpQuiz,cmpLesson;
public UserHelperClass() {
}
public UserHelperClass(String username, String email, String password, String cmpQuiz, String cmpLesson) {
this.username = username;
this.email = email;
this.password = password;
this.cmpQuiz = cmpQuiz;
this.cmpLesson = cmpLesson;
}
public String getCmpQuiz() {
return cmpQuiz;
}
public void setCmpQuiz(String cmpQuiz) {
this.cmpQuiz = cmpQuiz;
}
public String getCmpLesson() {
return cmpLesson;
}
public void setCmpLesson(String cmpLesson) {
this.cmpLesson = cmpLesson;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}}
HomeNavigationBottom Class. Code for BottomNavigationView
public class HomeNavigationBottom extends AppCompatActivity {
BottomNavigationView bottomNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_home_navigation_bottom);
bottomNavigationView = (BottomNavigationView)findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.action_dashboard:
selectedFragment = Dashboard.newInstance();
break;
case R.id.action_learning:
selectedFragment = Learning.newInstance();
break;
case R.id.action_profile:
selectedFragment = Profile.newInstance();
break;
case R.id.action_ranking:
selectedFragment = Ranking.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout,selectedFragment);
transaction.commit();
return false;
}
});
setDefaultFragment();
}
private void setDefaultFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout,Profile.newInstance());
transaction.commit();
}}
I think that's all I need to say, thank you for your time!
So you need to move recyclerAdapter.startListening(); from onCreate to onStart or onResume , because tabs of BottomNavigationView can be created and cached after you click it for the first time; if you go to other tabs, and return back then the cached version will be started/resumed without creating it again, and therefore the recyclerAdapter.startListening(); won't be triggered unless you click it for the second time to recreate it again.
Also for efficiency stop the listener in the opposite lifecycle method onPause or onStop using recyclerAdapter.stopListening();
i'm from indonesia, i want to refresh a fragment after i insert a data to it.. i have try many times to refresh a fragment. but it can't work.
please help me..
here's my code..
class MainActivity
public class MainActivity extends FragmentActivity {
public MainActivity() {
}
DatabaseReference dataBaseref;
StorageReference strRef;
TextView logout;
TabLayout tabLayout;
ViewPager viewPager;
ViewPagerAdapter viewAdapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataBaseref = FirebaseDatabase.getInstance().getReference();
strRef = FirebaseStorage.getInstance().getReference();
tabLayout = findViewById(R.id.tab_layout_isi_menu);
viewPager = findViewById(R.id.view_pager_isi_menu);
logout = findViewById(R.id.text_logout);
viewAdapter = new ViewPagerAdapter(getSupportFragmentManager(), MainActivity.this);
viewAdapter.addFragment(new isi_list_beli(), "Beli");
viewAdapter.addFragment(new isi_list_cek(), "Cek Data");
viewPager.setAdapter(viewAdapter);
tabLayout.setupWithViewPager(viewPager);
logout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
logOut();
}
});
}
private void logOut() {
AuthUI.getInstance()
.signOut(MainActivity.this)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
startActivity(new Intent(MainActivity.this, LoginActivity.class));
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(MainActivity.this, "" + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
#Override
protected void onResume() {
super.onResume();
}
public void onBackPressed() {
super.finish();
}
}
class isi_list_cek
public class isi_list_cek extends Fragment {
private ListView listView;
public AdapterListCek adapterListCek = null;
private ArrayList<Cek> cekArrayList;
Cursor cursor;
View view;
FloatingActionButton fab;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapterListCek = new AdapterListCek(getContext(), R.layout.item_in_list_barang, cekArrayList);
adapterListCek.notifyDataSetChanged();
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #NonNull Bundle savedInstanceState) {
view = inflater.inflate(R.layout.list_barang, container, false);
listView = view.findViewById(R.id.list_item_barang);
fab = view.findViewById(R.id.tambah_barang);
cekArrayList = new ArrayList<>();
adapterListCek = new AdapterListCek(getContext(), R.layout.item_in_list_barang, cekArrayList);
listView.setAdapter(adapterListCek);
cursor = fragment_input_data.sqlHelper.getData("SELECT * FROM CEK");
if(cursor.moveToFirst()){
cekArrayList.clear();
do{
int id = cursor.getInt(0);
String kode = cursor.getString(1);
String nama = cursor.getString(2);
String jumlah = cursor.getString(3);
String harga = cursor.getString(4);
byte[] gambar = cursor.getBlob(5);
cekArrayList.add(new Cek(id, kode, nama, harga, jumlah, gambar));
}while (cursor.moveToNext());
fragment_input_data.sqlHelper.close();
}
adapterListCek.notifyDataSetChanged();
listView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
return false;
}
});
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(getContext(), fragment_input_data.class));
}
});
return view;
}
#Override
public void onResume() {
super.onResume();
}
}
class ViewPagerAdapter
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private Context mContext;
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentListTitle = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fm, Context mContext) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentListTitle.size();
//return 2;
}
#NonNull
#Override
public CharSequence getPageTitle(int position) {
return fragmentListTitle.get(position);
}
public void addFragment (Fragment fragment, String string){
fragmentList.add(fragment);
fragmentListTitle.add(string);
}
}
i expect when i insert some data, fragment will automatically update it's view.
call a function as: just send the new instance of present fragment that you want to recreate
replaceFragment(new YourPresentFragment());
the function can be as below:
private void replaceFragment(Fragment fragment) {
String fragmentTag = fragment.getClass().getName();
FragmentManager manager = getFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.fragments, fragment, fragmentTag);
ft.addToBackStack("fragments");
ft.commit();
}
this should do the job
Hello need help with a class trying to figure out how to create a first and last button in a fragment that will jump to the first item in a ViewPager and the last item in a ViewPager I'm a bit lost with how to implement. Here is the fragment.
public class CrimeFragment extends Fragment {
private static final String ARG_CRIME_ID = "crime_id";
private static final String DIALOG_DATE = "DialogDate";
private static final int REQUEST_DATE = 0;
private Crime mCrime;
private EditText mTitleField;
private Button mDateButton;
private CheckBox mSolvedCheckBox;
private Spinner mSpinner;
private Button mFirstButton;
private Button mLastButton;
public static CrimeFragment newInstance(UUID crimeId) {
Bundle args = new Bundle();
args.putSerializable(ARG_CRIME_ID, crimeId);
CrimeFragment fragment = new CrimeFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_DATE) {
Date date =
(Date) data.getSerializableExtra(DatePickerFragment.EXTRA_DATE);
mCrime.setDate(date);
updateDate();
}
}
private void updateDate() {
mDateButton.setText(mCrime.getDate().toString());
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, container, false);
mTitleField = (EditText)v.findViewById(R.id.crime_title);
mTitleField.setText(mCrime.getTitle());
mTitleField.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(
CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(
CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
mDateButton = (Button) v.findViewById(R.id.crime_date);
updateDate();
mDateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager manager = getFragmentManager();
DatePickerFragment dialog = DatePickerFragment.newInstance(mCrime.getDate());
dialog.setTargetFragment(CrimeFragment.this, REQUEST_DATE);
dialog.show(manager, DIALOG_DATE);
}
});
mSpinner = (Spinner) v.findViewById(R.id.crime_severity);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getActivity(),
R.array.severity_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinner.setAdapter(adapter);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
mCrime.setSeverity((String) mSpinner.getSelectedItem());
}
#Override
public void onNothingSelected(AdapterView<?> parentView) {
}
});
mSolvedCheckBox = (CheckBox) v.findViewById(R.id.crime_solved);
mSolvedCheckBox.setChecked(mCrime.isSolved());
mSolvedCheckBox.setOnCheckedChangeListener(
new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
mCrime.setSolved(isChecked);
}
});
mFirstButton = (Button) v.findViewById(R.id.first_crime_button);
mFirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
mLastButton = (Button) v.findViewById(R.id.last_crime_button);
mLastButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
return v;
}
}
Here is the Activity with the ViewPager.
public class CrimePagerActivity extends FragmentActivity{
private static final String EXTRA_CRIME_ID = "com.martin.android.criminalintent.crime_id";
private ViewPager mViewPager;
private List<Crime> mCrimes;
public static Intent newIntent(Context packageContext, UUID crimeId) {
Intent intent = new Intent(packageContext, CrimePagerActivity.class);
intent.putExtra(EXTRA_CRIME_ID, crimeId);
return intent;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
UUID crimeId = (UUID) getIntent().getSerializableExtra(EXTRA_CRIME_ID);
mViewPager = (ViewPager) findViewById(R.id.activity_crime_pager_view_pager);
mCrimes = CrimeLab.get(this).getCrimes();
FragmentManager fragmentManager = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
#Override
public Fragment getItem(int position) {
Crime crime = mCrimes.get(position);
return CrimeFragment.newInstance(crime.getId());
}
#Override
public int getCount() {
return mCrimes.size();
}
});
for (int i = 0; i < mCrimes.size(); i++) {
if (mCrimes.get(i).getId().equals(crimeId)) {
mViewPager.setCurrentItem(i);
break;
}
}
}
}
For the First button Im pretty sure I just need to set item to 0? For last button I need to set item to size - 1 just not sure how to do that.
In your CrimePagerActivity, write two method's to jump to the ViewPager first page and last page.
CrimePagerActivity.java:
public void jumpToFirstPage() {
mViewPager.setCurrentItem(0);
}
public void jumpToLastPage() {
mViewPager.setCurrentItem(mCrimes.size() - 1);
}
Call those method's from mFirstButton and mLastButton click listener method:
CrimeFragment.java:
mFirstButton = (Button) v.findViewById(R.id.first_crime_button);
mFirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((CrimePagerActivity)getActivity()).jumpToFirstPage();
}
});
mLastButton = (Button) v.findViewById(R.id.last_crime_button);
mLastButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((CrimePagerActivity)getActivity()).jumpToLastPage();
}
});
Hope this will work perfectly.
Ok this was a answer that I was given by the teacher incase anyone is interested.
mFirstButton = (Button) v.findViewById(R.id.first_crime_button);
mFirstButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewPager pager = (ViewPager) getActivity().findViewById(R.id.activity_crime_pager_view_pager);
pager.setCurrentItem(0);
}
});
mLastButton = (Button) v.findViewById(R.id.last_crime_button);
mLastButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewPager pager = (ViewPager) getActivity().findViewById(R.id.activity_crime_pager_view_pager);
pager.setCurrentItem(CrimeLab.get(getActivity()).getCrimes().size()-1);
}
});
Create two button and on click set
viewPager.setCurrentItem(0); // for top
and
viewPager.setCurrentItem(mCrimes.size()); // for last