In my application , I have ViewPager containing 3 fragments (Home , Profile and More)
Home Fragment contain RecyclerView
when i navigate from Home Fragment to Profile Fragment or More Fragment, it work like expected.
But when i navigate back to Home Fragment , items in RecyclerView duplicate...
And when i navigate again and back , it duplicate again
Here is my MainActivity.java Code:
public class MainActivity extends AppCompatActivity {
TabLayout mainTabLayout;
ViewPager mainViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainTabLayout = findViewById(R.id.main_tablayout);
mainViewPager = findViewById(R.id.main_viewpager);
mainTabLayout.setupWithViewPager(mainViewPager);
//to put mainTabLayout Icons...
MainTabLayoutIcons();
}
//to Change MainLayout Icons...
private void MainTabLayoutIcons() {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
// add fragments to the adapter
adapter.addFragment(new Home());
adapter.addFragment(new MyActivity());
adapter.addFragment(new More());
mainViewPager.setOffscreenPageLimit(0);
mainViewPager.setAdapter(adapter);
// Select Home tab as default tab on startup
mainViewPager.setCurrentItem(0);
mainTabLayout.getTabAt(0).select();
// Set tabs Initial icons
mainTabLayout.getTabAt(0).setIcon(R.drawable.home_black);
mainTabLayout.getTabAt(1).setIcon(R.drawable.user_outline);
mainTabLayout.getTabAt(2).setIcon(R.drawable.more_outline);
/* tabSelectedListener to change the icon color once it is selected
// and change it back once another tab is selected */
mainTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (tab.getPosition() == 0) {
mainTabLayout.getTabAt(0).setIcon(R.drawable.home_black);
mainTabLayout.getTabAt(1).setIcon(R.drawable.user_outline);
mainTabLayout.getTabAt(2).setIcon(R.drawable.more_outline);
}
if (tab.getPosition() == 1) {
mainTabLayout.getTabAt(0).setIcon(R.drawable.home_outline);
mainTabLayout.getTabAt(1).setIcon(R.drawable.user_);
mainTabLayout.getTabAt(2).setIcon(R.drawable.more_outline);
}
if (tab.getPosition() == 2) {
mainTabLayout.getTabAt(0).setIcon(R.drawable.home_outline);
mainTabLayout.getTabAt(1).setIcon(R.drawable.user_outline);
mainTabLayout.getTabAt(2).setIcon(R.drawable.more_black);
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
//no need for it
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
//no need for it
}
});
}
}
and here is ViewPagerAdapter Code:
//Adapter for mainActivity ...
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
public ViewPagerAdapter(#NonNull FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
public void addFragment(Fragment fragment) {
fragmentList.add(fragment);
}
}
and here is first Fragment Home.java Code:
public class Home extends Fragment {
View v;
public SwipeRefreshLayout mSwipeRefreshLayout;
public RecyclerView mainRecyclerView;
private LinearLayoutManager linearLayoutManager;
public final List<MyActivityModel> mainPosts = new ArrayList<>();
private PostAdapter mAdapter;
public Home() {
/*Required Empty Constructor... */
}
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle bundle) {
v = layoutInflater.inflate(R.layout.fragment_home, container, false);
mSwipeRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.mainSwipeRefresh);
mainRecyclerView = (RecyclerView) v.findViewById(R.id.MainRecyclerView);
linearLayoutManager = new LinearLayoutManager(getActivity());
mainRecyclerView.setLayoutFrozen(true);
mainRecyclerView.setNestedScrollingEnabled(false);
mainRecyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new PostAdapter(mainPosts);
mainRecyclerView.setAdapter(mAdapter);
Swipe();
LoadPosts();
return v;
}
/**
* -----------------TODO: to load posts in Home RecyclerView...----------------
*/
public void LoadPosts() {
Query database = FirebaseDatabase.getInstance().getReference().child("Posts");
database.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
if (snapshot.exists()) {
MyActivityModel post = snapshot.getValue(MyActivityModel.class);
mainPosts.add(0, post);
mAdapter.notifyDataSetChanged();
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot snapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
private void Swipe() {
//to refresh page after swipe
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
mainPosts.clear();
LoadPosts();
mSwipeRefreshLayout.setRefreshing(false);
Toast.makeText(v.getContext(),"Refreshed", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
mSwipeRefreshLayout.setRefreshing(false);
}
}
}, 500);
}
});
}
}
and this is an image showing item reeating
Anyone can help me how to prevent this duplication...
You may need to use FragmentPagerAdapter instead of FragmentStatePagerAdapter. Also, set mainRecyclerView.setLayoutFrozen(true); to false because, it will stop everything in recyclerView.
When you need to use FragmentPagerAdapter?
FragmentStatePagerAdapter is more useful when there are a large number
of pages, working more like a list view. When pages are not visible to
the user, their entire fragment may be destroyed, only keeping the
saved state of that fragment. This allows the pager to hold on to
much less memory associated with each visited page as compared to
FragmentPagerAdapter at the cost of potentially more overhead when
switching between pages.
Example of FragmentPagerAdapter:
class viewpager_class extends FragmentPagerAdapter {
int tabcount;
public viewpager_class(#NonNull FragmentManager fm, int tab_count) {
super(fm, tab_count);
this.tabcount = tab_count;
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
Fragment1 fragment1 = new Fragment1 ();
return todayBAFragment;
case 1:
Fragment2 fragment2 = new Fragment2 ();
return todayReminderDue;
case 2:
Fragment3 fragment3 = new Fragment3 ();
return currentTransaction;
default:
return null;
}
}
#Override
public int getCount() {
return tabcount;
}
}
Also, set adapter into ViewPager wherever you want show viewPager:
//set adapter into viewpager
viewpager_class viewpagerClass = new viewpager_class(getChildFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(viewpagerClass);
viewPager.setOffscreenPageLimit(2);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
Related
I'm working on my school project with Firebase firestore and firebase Auth. It's something like a Kanban app.
My intend is to add delete documents from database while slide, and move documents to another catalog while sliding left-right. My main activity (TestActivity) is tabbed, so I want the deletion or moving to depend on direction and actual tab. Each tab have own Recycle View. You know: To do, In progress, Done.
I tried to follow Code Flow: https://www.youtube.com/watch?v=ub6mNHWGVHw&list=PLrnPJCHvNZuAXdWxOzsN5rgG2M4uJ8bH1
but my project need fragments, and with them, his "NoteAdapter" doesn't work. I found this tutorial: https://www.youtube.com/watch?v=FFHuYcB3YnU
and used it to place the adapter in right fragment.
Everything works until I want to do something with the firebase documents. This doesn't work at all or I just don't have idea where to place it:
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
adapter.deleteItem(viewHolder.getAdapterPosition());
}
}).attachToRecyclerView(recyclerView);
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
Im using firebase and fragments first time.
Here comes some of my code: TestActivity (my main, I have also a drawer with user info and signout button, but this button which doesn't work,too):
public class TestActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private TabLayout tabLayout;
private ViewPager viewPager;
private SectionsPagerAdapter adapter;
private DrawerLayout drawer;
FirebaseAuth mAuth;
FirebaseUser currentUser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Toolbar toolbar = findViewById(R.id.toolbar); // toolbar staje sie action bar
setSupportActionBar(toolbar);
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
mAuth = FirebaseAuth.getInstance();
currentUser = mAuth.getCurrentUser();
updateNavHeader();
viewPager = findViewById(R.id.view_pager);
tabLayout = findViewById(R.id.tabs);
adapter = new SectionsPagerAdapter(getSupportFragmentManager());
adapter.AddFragment(new TodoFragment(), "To Do");
adapter.AddFragment(new InprogressFragment(), "In Progress");
adapter.AddFragment(new DoneFragment(), "Done");
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
FloatingActionButton fab = findViewById(R.id.add_todo);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Add new item", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
updateUI();
}
});
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
// po zalogowaniu dane w drawer sie zmienia
public void updateNavHeader() {
NavigationView navigationView =(NavigationView) findViewById(R.id.nav_view);
View headerView = navigationView.getHeaderView(0);
TextView navUserName = headerView.findViewById(R.id.nav_username);
TextView navUserEmail = headerView.findViewById(R.id.nav_useremail);
ImageView userAvatar = headerView.findViewById(R.id.nav_useravatar);
navUserName.setText(currentUser.getDisplayName());
navUserEmail.setText(currentUser.getEmail());
if (currentUser.getPhotoUrl() != null) {
Glide.with(this).load(currentUser.getPhotoUrl()).into(userAvatar);
} else {
Glide.with(this).load(R.drawable.userphoto).into(userAvatar);
}
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
if (item.getItemId() == R.id.nav_signout) {
FirebaseAuth.getInstance().signOut();
Intent loginActivity = new Intent(getApplicationContext(), LoginActivity.class);
startActivity(loginActivity);
finish();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void updateUI() {
Intent NewActivity = new Intent(getApplicationContext(), NewActivity.class);
startActivity(NewActivity);
finish();
}
}
TodoFragment:
public class TodoFragment extends Fragment {
private View v;
private RecyclerView recyclerView;
FirebaseFirestore db = FirebaseFirestore.getInstance();
CollectionReference TodoRef= db.collection("ToDo");
FirebaseAuth mAuth;
String Uemail;
public TodoFragment() {
// Required empty public constructor
}
public static TodoFragment newInstance() {
TodoFragment fragment = new TodoFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
Query q =TodoRef.whereEqualTo("email", Uemail);
FirestoreRecyclerOptions options=new FirestoreRecyclerOptions.Builder<Item>().setQuery(q, Item.class).build();
FirestoreRecyclerAdapter<Item, ItemViewHolder>adapter= new FirestoreRecyclerAdapter<Item, ItemViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull ItemViewHolder itemViewHolder, int i, #NonNull Item item) {
itemViewHolder.textViewItem.setText(item.getTextitem());
}
#NonNull
#Override
public ItemViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
ItemViewHolder viewHolder = new ItemViewHolder(v);
return viewHolder;
}
};
recyclerView.setAdapter(adapter);
adapter.startListening();
}
public static class ItemViewHolder extends RecyclerView.ViewHolder{
TextView textViewItem;
public ItemViewHolder(#NonNull View itemView) {
super(itemView);
textViewItem = itemView.findViewById(R.id.item_text);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_todo, container, false);
recyclerView = v.findViewById(R.id.recycler_view_todo);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mAuth=FirebaseAuth.getInstance();
Uemail= mAuth.getCurrentUser().getEmail();
return v;
}
}
My Item class:
public class Item {
private String textitem;
private String email;
public Item(){
//needed
}
public Item(String textitem, String email) {
this.email=email;
this.textitem=textitem;
}
public String getTextitem() {
return textitem;
}
public void setTextitem(String textitem) {
this.textitem = textitem;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
}
And my Section Pager Adapter:
public SectionsPagerAdapter( FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
#Override
public int getCount() {
return titles.size();
}
public void AddFragment(Fragment fragment, String title ){
fragments.add(fragment);
titles.add(title);
}
}
I did my best to find the solution on my own, but I apparently failed.
EDIT:
I finally found out how to handle it.
I moved adapter to independent class again, but with little changes in both fragments and adapter.
My adapter now: (with moving and deleting docs in Firestore)
public class ItemAdapter extends FirestoreRecyclerAdapter<Item, ItemAdapter.NoteHolder> {
public ItemAdapter(#NonNull FirestoreRecyclerOptions<Item> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull NoteHolder holder, int position, #NonNull Item model) {
holder.textViewTitle.setText(model.getTextitem());
}
#NonNull
#Override
public NoteHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
parent, false);
return new NoteHolder(v);
}
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
Log.d("Firestore", "DocumentSnapshot successfully deleted!");
}
public void moveItem(int position, CollectionReference ColRef) {
DocumentReference from= getSnapshots().getSnapshot(position).getReference();
DocumentReference to =ColRef.document();
moveFirestoreDocument( from, to);
}
public void moveFirestoreDocument(final DocumentReference fromPath, final DocumentReference toPath) {
fromPath.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document != null) {
toPath.set(document.getData())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("Firestore", "DocumentSnapshot successfully written!");
fromPath.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d("Firestore", "DocumentSnapshot successfully deleted!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w("Firestore", "Error deleting document", e);
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w("Firestore", "Error writing document", e);
}
});
} else {
Log.d("Firestore", "No such document");
}
} else {
Log.d("Firestore", "get failed with ", task.getException());
}
}
});
}
class NoteHolder extends RecyclerView.ViewHolder {
TextView textViewTitle;
public NoteHolder(View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.item_text);
}
}
}
And my Fragment now looks like this:
public class TodoFragment extends Fragment {
private View v;
private RecyclerView recyclerView;
FirebaseFirestore db = FirebaseFirestore.getInstance();
CollectionReference TodoRef = db.collection("ToDo");
CollectionReference InProgRef = db.collection("InProgress");
ItemAdapter adapter;
FirebaseAuth mAuth;
String Uemail;
public TodoFragment() {
}
public static TodoFragment newInstance() {
TodoFragment fragment = new TodoFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_todo, container, false);
recyclerView = v.findViewById(R.id.recycler_view_todo);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mAuth=FirebaseAuth.getInstance();
Uemail= mAuth.getCurrentUser().getEmail();
setUpRecyclerView(recyclerView);
return v;
}
private void setUpRecyclerView(RecyclerView recyclerView) {
Query q =TodoRef.whereEqualTo("email", Uemail);
FirestoreRecyclerOptions<Item> options = new FirestoreRecyclerOptions.Builder<Item>()
.setQuery(q, Item.class)
.build();
adapter = new ItemAdapter(options);
recyclerView.setAdapter(adapter);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT|ItemTouchHelper.UP) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int right = 8;
if(direction==right){
adapter.moveItem(viewHolder.getAdapterPosition(),InProgRef);
}else{
adapter.deleteItem(viewHolder.getAdapterPosition());
}
}
}).attachToRecyclerView(recyclerView);
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
To sum up:
setUpRecyclerView function neded to get the right Recycler View as an argument, without it there was NullPointer Excepction all the time.
I made a mistake with wrong layout in inflaters, too
Hope it will be usefull for somebody.
I'm using Fragments to change scenes in my application, and I've come across the problem where when the phone back button is pressed, the application closes. How would I make it so when the back button is pressed, the previous fragment opens.
I searched for solutions and there are quite a few like using getChildFragmentManager or back stack. I just don't know how to implement it for my specific state pager adapter, of which I followed a youtube video tutorial for.
SectionsStatePagerAdapter.java:
public class SectionsStatePagerAdapter extends FragmentStatePagerAdapter {
private final ArrayList<Fragment> mFragmentList = new ArrayList<>();
private final ArrayList<String> mFragmentTitleList = new ArrayList<>();
public SectionsStatePagerAdapter(#NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
public SectionsStatePagerAdapter(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
public void addFragment(Fragment fragment, String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#NonNull
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
}
MainActivity.java:
public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {
public SectionsStatePagerAdapter mSectionsStatePagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Fragment Stuff:
mSectionsStatePagerAdapter = new SectionsStatePagerAdapter(getSupportFragmentManager());
mViewPager = findViewById(R.id.container);
//SetUpPager:
setupViewPager(mViewPager);
}
private void setupViewPager(ViewPager viewPager){
SectionsStatePagerAdapter adapter = new SectionsStatePagerAdapter(getSupportFragmentManager());
adapter.addFragment(new MainPageFragment(),"MainPage"); //0
adapter.addFragment(new CoffeePageFragment(),"CoffeePage"); //1
adapter.addFragment(new RegularCoffeeFragment(),"RegularCoffeePage"); //2
viewPager.setAdapter(adapter);
}
public void setViewPager(int fragmentNumber){
mViewPager.setCurrentItem(fragmentNumber);
}
}
CoffeePageFragment.java:
public class CoffeePageFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_coffee_page,container,false);
btnRegularCoffee = view.findViewById(R.id.regular_coffee_button);
btnRegularCoffee.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity)getActivity()).setViewPager(2);
}
});
return (view);
}
}
In conclusion, how do I make it so when the device back button is pressed, it will go back to the previous fragment?
In previous versions of the AppCompatActivity implementation it was enough to override onBackPressed() in your activity, newer versions dictate to implement the OnBackPressedCallback, like shown here: https://developer.android.com/reference/androidx/activity/OnBackPressedDispatcher.html
public class FormEntryFragment extends Fragment {
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
OnBackPressedCallback callback = new OnBackPressedCallback(
true // default to enabled
) {
#Override
public void handleOnBackPressed() {
showAreYouSureDialog();
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(
this, // LifecycleOwner
callback);
}
}
It might still be ok to use onBackPressed on the Activity level, though.
Not able to pass the retrived list of data from retrofit to a recyclerview in fragment!
Tried some solutions but not working!
I have tried creating methods in fragment and passing but not working!
Getting null!
Activity
TabLayout tabLayout;
ViewPager viewPager;
RecyclerView recyclerView;
//vars
private Dto dto;
List<Post_DTO> post_dto_list=new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState)
{
dto=new Dto();
UpdateList();
super.onCreate(savedInstanceState);
setContentView(R.layout.home_layout);
tabLayout=(TabLayout)findViewById(R.id.tabLayout);
viewPager=(ViewPager)findViewById(R.id.viewPager);
tabLayout.addTab(tabLayout.newTab().setText("Dashboard"));
tabLayout.addTab(tabLayout.newTab().setText("Converations"));
tabLayout.addTab(tabLayout.newTab().setText("Profile"));
PostFragment pf=new PostFragment();
pf.passData(getApplicationContext(),post_dto_list);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//ft.add(R.id.posts_recyclerview, ft);
ft.addToBackStack(null);
ft.commit();
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
final MyAdapter adapter = new MyAdapter(this,getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
System.out.println(tab.getPosition());
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
private void UpdateList() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(getString(R.string.postUrl))
.addConverterFactory(GsonConverterFactory.create())
.build();
PostsInterface postsInterface =retrofit.create(PostsInterface.class);
Call<Post_DTO_Resp> call= postsInterface.getPosts();
call.enqueue(new Callback<Post_DTO_Resp>() {
#Override
public void onResponse(Call<Post_DTO_Resp> call, Response<Post_DTO_Resp> response) {
//pDialog.dismiss();
if(!response.isSuccessful())
{
Toast.makeText(getApplicationContext(),"Loading the posts!",Toast.LENGTH_SHORT).show();
}
Post_DTO_Resp posts = response.body();
post_dto_list=posts.getPost_dto_list();
//dto.setList(post_dto_list);
}
#Override
public void onFailure(Call<Post_DTO_Resp> call, Throwable t) {
//pDialog.dismiss();
if(t.getMessage().equals("End of input at line 1 column 1 path $"))
{
Toast.makeText(getApplicationContext(), "There are no posts!", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(getApplicationContext(), "Api Error!", Toast.LENGTH_LONG).show();
}
}
});
}
}
Fragment!
public class PostFragment extends Fragment {
RecyclerView recyclerView;
View v;
Dto dtobject;
private static final String DESCRIBABLE_KEY = "list";
private Describable mDescribable;
List<Post_DTO> post_dto_list;
public PostFragment() {
// Required empty public constructor
}
public void passData(Context context, List<Post_DTO> list) {
//mContext = context;
post_dto_list = list;
// mIndex = pos;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_posts, container, false);
recyclerView=(RecyclerView) v.findViewById(R.id.posts_recyclerview);
RecyclerViewAdapter recyclerViewAdapter=new RecyclerViewAdapter(getContext(),post_dto_list);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(recyclerViewAdapter);
//listupdater();
return v;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Just want to get the post_dto_list from Activity to fragment class!
Suggestions please!
You can use a bundle to pass a list from activity to fragment.
In activity:
Bundle bundle = new Bundle();
bundle.putSerializable("list", mList);
mFragment.setArguments(bundle);
And then in your fragment:
mList = getIntent().getExtras().getSerializable("list"));
But the POJO that your list contains should be parcelable ( Parcelable better than Serializable).
Your POJO should be something like:
public class MyPOJO implements Parcelable {
For more info refer this.
I got a problem with updating ViewPager fragments. We need to show fragments with data to registered user, when he doesn't registered we need to show fragments with message to register. I use this method to check it in MainActivity:
#Override
public void setAdapter(boolean isUserExist) {
Log.d("RegDebug", "In setAdapter");
mainPagerAdapter.clearData();
mainPagerAdapter.addFragment(searchFragment, getString(R.string.search_title));
if (isUserExist) {
Log.d("RegDebug", "In setAdapter reg");
mainPagerAdapter.addFragment(new ChatsFragment(), getString(R.string.chats_title));
mainPagerAdapter.addFragment(new ActionsFragment(), getString(R.string.actions_title));
Toast.makeText(getApplicationContext(), "Registered!", Toast.LENGTH_SHORT).show();
} else {
Log.d("RegDebug", "In setAdapter unreg");
mainPagerAdapter.addFragment(RegisterFragment.newInstance(Consts.CHATS_TAB_NAME), getString(R.string.chats_title));
mainPagerAdapter.addFragment(RegisterFragment.newInstance(Consts.ACTIONS_TAB_NAME), getString(R.string.actions_title));
Toast.makeText(getApplicationContext(), "Unregistered!!!", Toast.LENGTH_SHORT).show();
}
mainPagerAdapter.notifyDataSetChanged();
viewPager.setAdapter(mainPagerAdapter);
}
I call this method in presenter with setting value from firebase auth, checking if user exists:
public void checkForUserExist() {
if (mainInteractor.isUserExist()) {
getViewState().setRegAdapter();
} else getViewState().setUnregAdapter();
}
And then call presenter method in onCreate of MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dialogFragment = new FilterDialogFragment();
searchFragment = new SearchFragment();
//UI
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager = findViewById(R.id.main_view_pager);
tabLayout = findViewById(R.id.main_tabs);
//mainPagerAdapter = new MainPagerAdapter(getSupportFragmentManager());
mainPresenter.checkForUserExist();
tabLayout.setupWithViewPager(viewPager);
}
I try to log the boolean result and it returns exactly value that must be, but pager adapter can't update its content.Code of MainPagerAdapter:
public class MainPagerAdapter extends FragmentPagerAdapter{
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> fragmentTitleList = new ArrayList<>();
public MainPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentTitleList.size();
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
public void addFragment(Fragment fragment, String title){
fragmentList.add(fragment);
fragmentTitleList.add(title);
}
public void clearData(){
fragmentList.clear();
fragmentTitleList.clear();
notifyDataSetChanged();
Log.d("RegDebug", " fragmentList size is " + fragmentList.size()
+ " fragmentTitleList size is " + fragmentTitleList.size());
}
}
Use OnPageChangeListener of ViewPager class & notify to your current fragment from there using interface.
in my app i have a Tabs with fragment classes. i trying to refresh listView in "fragment a" with the new data i insert.
In "fragment b" i have EditText and Button ,that inserting text to the database.
in "fragment a" i have the ListView with the dataBase rows. when "fragment a" is "OnCreateView" i just put the dataBase on a "ArrayList" and past it to my baseAdapter.
but "onCreateView" not refreshing my new data every time i get into the "fragment a" else i goes to "fragment c" and "onDestroy" call on "fragment a".
so my result it was to call : "setUserVisibleHint" override method, and check if it is visible and refreshing the list.
but i dont think it is the good practice .
what should i do?
Class a
public class ListFragment extends Fragment{
basAdapterCustom adapter;
ListView lv;
ArrayList<Clock> list;
private DbHandler hand;
Context context;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.list_fragment, container, false);
context = getActivity();
Log.d(TAG, "onCreateView");
hand = new DbHandler(context);
list = new ArrayList<Clock>();
lv = (ListView) v.findViewById(R.id.listOfShifts);
adapter = new basAdapterCustom(list, getActivity());
lv.setAdapter(adapter);
refreshList();
return v;
}
//like on "resume":
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
// Make sure that we are currently visible
if (this.isVisible()) {
refreshList();
if (!isVisibleToUser) {
// TODO stop
}
}
}
private void refreshList() {
list = hand.getByWorkName();
adapter = new basAdapterCustom(list,getActivity());
lv.setAdapter(adapter);
}
class b:
public class ClockFragment extends Fragment{
DbHandler hand;
Context context;
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.clock, container,false);
context = getActivity();
hand = new DbHandler(context);
return v;
}
// ADD to .Db
public void addToDb(View v){
hand.add(new Clock(0, dateDay));
}
}
class mainActivity:
public class MainActivity extends FragmentActivity implements ActionBar.TabListener, OnPageChangeListener{
public static final String TAG = "myClock";
String[] tabMenu = {"FRAG A","FRAG B","FRAG C"};
private ViewPager viewPager;
private TabPagerAdapter mAdapter;
private ActionBar actionBar;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(MainActivity.TAG, "OnCreate = MainActivity (Pager");
viewPager = (ViewPager) findViewById(R.id.pager );
actionBar = getActionBar();
mAdapter = new TabPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tabsNames : tabMenu) {
actionBar.addTab(actionBar.newTab().setText(tabsNames).setTabListener(this));
}
viewPager.setOnPageChangeListener(this);
}
// public void transDialog(){
// Dialog mDialog = new Dialog(this, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
// }
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
}
PagetAdapter.class
public class TabPagerAdapter extends FragmentPagerAdapter {
private static final String TAG = "myClock";
public TabPagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}
#Override
public Fragment getItem(int index) {
Log.d(TAG, " CLASS : TabPagerAdapter");
switch (index) {
case 0:
return new ListFragment();
case 1:
return new ClockFragment();
case 2:
return new SettingFragment();
default:
break;
}
Log.d(TAG, " CLASS : TabPagerAdapter = "+index);
return null;
}
#Override
public int getCount() {
return 3;
}
}
Please help me i hope you are understand my problem...
You want to update listView in fragment A, after insert data in fragment b? ThenĀ you have a few solutions to choose:
1. Implement communications between fragments via activity. Then B insert date, it send message to activity, that data need to be updated. Then fragment A started, it's ask activity to need update data. For details on implementing this communication check link.
2. Use some bus library, EventBus for example. Then fragment B insert data, it post 'data changed' event to bus. Fragment A checks on start if this event occurs.
3. Use Loaders which "monitor the source of their data and deliver new results when the content changes."