I have 5 fragments in an activity. And they are being showed using tabs/viewpager. Suppose they are nameD as ONE, TWO, THREE, FOUR and FIVE. I am displaying data in all fragments as ListView. I am inflating data in ListView from database cursor. The data is updated normally when i perform an add or delete in the same fragment. The problem occurs when i send/move a data from one fragment to another.
EXAMPLE OF PROBLEM:
I send/move data from fragment ONE to fragment TWO. Then I tap on fragment TWO to view data. It is not there. The data is shown when I tap on fragment FOUR or fragment FIVE and then come back to fragment ONE. Or if the app is restarted or any other Activity comes in front and goes back.
The data is not shown by clicking the adjacent tabs or swapping to adjacent tabs. And then coming back to the tab from which data was moved
I am sure someone of you must have an idea whats happening here and tell me how to solve the issue.
onCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag_dramas, container, false);
setHasOptionsMenu(true);
list = (ListView) view.findViewById(R.id.mylist);
return view;
}
onResume
#Override
public void onResume() {
super.onResume();
getListView();
}
onViewCreated
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
add();
}
});
}
There are other methods in the fragment too but they are not relevant to the issue. I Think these three methods are relevant. And i have no onCreate() method in the fragment..
If Fragment is already in the memory you should use BroadcastReceiver to notify other fragments whenever any data is added/removed/updated.
You can try EventBus as well.
https://github.com/greenrobot/EventBus
Related
I have implemented some fragments which are hosted by a single Activity (they're in the same activity). In one of these fragments (Let's say fragment A), I have a vertical recyclerview.
The problem is arises when I want to navigate from Fragment A to other fragments (Again, in the same activity). Suppose that I'm clicking the middle member of the list, then I navigate to the next fragment. When I want to back into the first fragment (Fragment A), it inflates the list from first. Seeming that it looses its position, however, using onSaveInstanceState() and also onCreateView(), I try to store and restore the selected item's position every time I quit or enter the fragment.
I think this issue may be originated from fragments' lifecycle which all are in one single activity. As this answer, mentioning :
In a Fragment, all of their lifecycle callbacks are directly tied to their parent Activity. So onSaveInstanceState gets called on the Fragment when its parent Activity has onSaveInstanceState called.
and that's why I emphasize on the "single" activity. How can we handle such situation?
I have debugged my program and onSaveInstanceState and onCreateView were not even called when they were supposed to. Below is my attempted code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!=null){
selectedItem = savedInstanceState.getInt(BUNDLE_KEY_SELECTED_ITEM);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null){
selectedItem = savedInstanceState.getInt(BUNDLE_KEY_SELECTED_ITEM);
}
myRecyclerView = (RecyclerView) v.findViewById(R.id.rv_mine);
// mData is a an ArrayList
myAdapter = new MyAdapter(mData, getContext(), this.selectedItem);
myLayoutManager = new LinearLayoutManager(getActivity());
myRecyclerView.setLayoutManager(myLayoutManager);
myRecyclerView.setAdapter(myAdapter);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt(BUNDLE_KEY_SELECTED_ITEM,selectedItem);
super.onSaveInstanceState(outState);
}
Well you can use .add() to add fragments to your activity than .replace(), Which preserves the state of the fragment within the activity, and if using replace function which will cause the onCreateView callback to trigger again.
I have a Navigation Drawer with 6 Fragments. One of them should contain a ListView. I got it to work and I can switch through all the Fragments via the Navigation Drawer. When I press on the one containing the ListView I can see it, just as it should be. However, when I go to the same Fragment (containing the ListView) while I'm in it already, the ListView isn't displayed anymore. This is probably due to the fact, that I set the ListView on the onActivityCreated() method in the Fragment. I'm curious now though, what happens when I press on the same Fragment again. Does the activity stay loaded and the Fragment needs to be inflated again and through this the OnActivityCreated() method isn't called again? And if so, what do I have to do, that the ListView gets displayed again?
My Fragment.class currently looks like this:
public class FahrplanFragment extends Fragment {
private ListView listView;
private Resources res;
private String[] plans;
private ArrayAdapter<String> adapter;
public FahrplanFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_fahrplan, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView = (ListView) getActivity().findViewById(R.id.listview_fahrplan);
res = getResources();
plans = res.getStringArray(R.array.plans);
adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,
android.R.id.text1, plans);
listView.setAdapter(adapter);
}
}
As in the documentation
Called when the fragment's activity has been created and this
fragment's view hierarchy instantiated. It can be used to do final
initialization once these pieces are in place, such as retrieving
views or restoring state. [..] This is called after
onCreateView(LayoutInflater, ViewGroup, Bundle) and before
onViewStateRestored(Bundle).
It is called every time. You can check by logging the event.
Can you post the code of the event handling when click on the navagition drawer button?
EDIT 1
Here I re-created you project to test it and it works. The fragment loads every time with the list view inside. Moreover, it displays the events when they happens and shows clearly that onActivityCreated is called every time the fragment is replaced.
The best suggestion I can give here is to log your code using Log.d() or System.out.println("...") in various steps of the code, or even better enter in debug mode by setting breakpoints and inspect the code while it's running to understand when it enter in some methods and when not.
I have five fragments a user can switch between. One of these fragments loads a list of users from the server to populate the UI list on the fragment. I need the list information to persist if a user swipes to a different fragment and then swipes back to the original. I do not want the fragment to reload the users every time a user leaves the fragment and goes back.
I am looking at setRetainInsance(true) and was wondering if this is possible solution? What would be the best way for the fragment to retain the information without being created from scratch each time.
I am using this to switch between fragements -getSupportFragmentManager().beginTransaction().replace(R.id.searchLayout, ratingFragment).commit();
A Fragment is Just like any other object.
on Fragment transaction , the Fragment does not call OnCreate() method instead it starts from onCreateView , therefore , load your users and save it an instance variable and assign it in onCreate()
Example
class MyFragment extends Fragment{
List<users> userList;
void onCreate(){
userList = getUserList();}
//the list is loaded during Oncreate();
now imagine you have replaced the Fragment
now According to Andorid Framework , onCreate() is not Called again
instead onCreateView() is called
void onCreateView(){
//you can check whether instance Variable is initialised or not
if(userList != null) {
listview.setAdapter(new Myadapter(this,userList);
Replace the fragment by adding it to backstack.
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(tag);
fragmentTransaction.replace(container, fragment, tag);
fragmentTransaction.commit();
Also create object of View and return it if it's not null.
private void View view ;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
if (view != null)
return view;
view = inflater.inflate(R.layout.fragment_browse_recipe, container, false);
//initialize layout views
return view;
}
I'm creating an application with a CustomPagerAdapter that can be controlled by ActionBar tabs or horizontal swipe. When you select a tab, a fragment corresponding to that tab is displayed on the screen. When the app is created and when any tab is selected, the adjacent tabs, fragments are loaded into memory. I do not want this to happen. I would like it so that when a tab is selected only that selected tab's fragment is loaded into memory. Is there a way to do this?
Edit: The code I'm currently having trouble with is as follows:
public class fragA extende Fragment
{
private VideoView videoViewA;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_A, container, false);
videoViewA = (VideoView) rootView.findViewById(R.id.videoViewA);
return rootView;
}
#Override
public void setUserVisibleHint(final boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser)
{
videoViewA.setVideoURI(LINK);
videoViewA.start();
}
else
{
videoViewA.stopPlayback();
}
}
}
The error I'm receiving is at the videoViewA.setVideoURI(LINK); line. Mind you, the link is actually there, but for privacy reasons I cannot post it.
Edit 2: It's ajava.lang.NullPointerException.
Edit 3: Sorry, but I'm doing this all the hard way. The code now reflects what I have actually written.
Try loading your videos within setUserVisbleHint(), which gets fired by the FragmentPageAdapter upon showing the fragment.
http://developer.android.com/reference/android/support/v4/app/Fragment.html#setUserVisibleHint(boolean)
If that doesn't work for you, you can also try to do check onHiddenChanged(boolean hidden).
http://developer.android.com/reference/android/app/Fragment.html#onHiddenChanged(boolean)
I have a tabbed application using fragments. Following is a code snippet from one of the fragments in tabA
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
accountsView = inflater.inflate(R.layout.activity_accounts, viewGroup, false);
//obtain the labels- Top 50 Spending aacounts
spendingLabel = (TextView) accountsView.findViewById(R.id.textView1);
//get search box
accountSearch = (EditText) accountsView.findViewById(R.id.vAccountSearch);
return accountsView;
}
Here is the onStart()
#Override
public void onStart() {
super.onStart();
fillData();
}
fillData() fetches dat from the server. The application now fills a listView on tab click (by calling fillData() ). If I switch to other tabs and come to tabA, the page again calls fillData() and recreates the whole view.
How do I stop it reloading and keep the view unchanged on tab switching?
Since I am a newbie into Fragments, I find it hard to find a solution. Has anyone dealt this before?
According to the lifecycle of Android application try to override onCreate instead of onStart
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fillData();
}