Switch current fragment on item click - android

I am trying to write a file manager for android as an university project. My idea is to use fragments in it to create a tabbed vew for it with a viewpager. Practically, the first view you get when you load the app is a path selection fragment, where you have sdcard, music, etc. That fragment contains a listview of said folders. When I click on an item, i want another fragment to be added to the pager, and that works fine. But I also want the current fragment to be replaced with a grid view of the "clicked" folder. That doesn't work. I use an arraylist of File[] to store files in each folder i selected. I also added methods inside the fragment adapter to add and replace fragments in my fragment arraylist. Tried with transaction and with my list, the list is correctly updated but the view is not. The following code is the method inside my fragment adapter to replace a fragment. It is called inside an onItemclicklistenr set to my listview:
public void replaceFragment(SherlockFragment newFragment, int pos) {
SherlockFragment old=fragments.get(pos);
fragments.set(pos, newFragment);
notifyDataSetChanged();
}
I read several answers about this issue, tried almost everything, nothing seems to work. Any help would be apreciated.

I found an horrible solution. After updating the fragment list (without fragmenttransaction) I re-set the adapter for the view pager and restore the current Item. This way I force the fragments layouts to be built. Not beautiful, but whatever. This is the interface that gets called onclick:
#Override
public void onPathSelected(int position) {
// TODO Auto-generated method stub
Log.d("positioninsideintfc", Integer.toString(position));
firstrun.add(true);
int current=mPager.getCurrentItem();
root=(File) filepaths.get(position);
fragmentfilelists.add(root.listFiles());
initpath=MainActivity.root.getAbsolutePath();
Gridfragment newfrag=Gridfragment.newInstance(current);
mAdapter.addFragment(Selectpathfragment.newInstance(current+1));
mAdapter.replaceFragment(newfrag, current);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(current);
}

You should learn your Activity to speak the language your frament use. In general your Activity should implement Interface which then your fragments will use for communication. So in your case, when user tap the list item, the fragment with listview shall tell its parent Actity (using said interface) something like "user clicked on this". And your parent activity should do the rest, replacing/adding fragments. Your fragment, like in OOP, shall be not aware of existence of other fragments.

Related

Interface from one fragment to another android

I am facing a problem implementing an interface defined in one fragment and using it to another. I know I need to do this through activity but I have added fragments dynamically inside another fragment. Please look at the snapshot to understand more about my problem.
. I have a fragment called ACTIVITY fragment inside which I load fragments dynamically. The Comments textview is clickable and when clicked it a CommentDialogFragment is shown. This dialog fragment is shared by all the fragments. Code when comment clicked:
FragmentTransaction ft = getActivity()
.getSupportFragmentManager().beginTransaction();
CommentDialog fragment = CommentDialog.newInstance(id,
"Activity");
ft.addToBackStack(null);
fragment.show(ft, null);
I want to increment the comment count. For that I made an interface:
public interface IncrementComment {
public void increaseCommentCount(boolean increase);
}
I am unable to use this interface in my fragment inside the ACTIVITY fragment. The interface is detected on the Activity that holds all these fragments. Heres the interface in my MainActivity class I get the data upto this point:
#Override
public void increaseCommentCount(boolean increase) {
// TODO Auto-generated method stub
Log.d("interface main activity", "called");//this is called
}
Now I am unable to pass data from this activity code to my fragment because the fragments are loaded dynamically and there can be any number of fragments(user can see their old post).
So I tried to make a fragment implement the interface to update the value of the textview. But I couldnot get it working as it is never called. Can someone point me in the correct direction. I tried most of the links in SO like this and from other sources like this but none of them fit my requirement.

My fragments in viewpager tab dont refresh

i got viewpager with 4 tabs .. in each tab there is a fragment.
my first tab is a fragment with a form (for example Users)
after i click save, the data is inserted in the database.
my second tab is another fragment with form but it uses data from the first tab (i am getting it from the database) to populate a spinner.
now after i successfully inserted data from my first tab, in my second tab the spinner is empty. since my db query is implemented in onCreateView() in the second fragment, its called only once when the application is started, so changing between tab 1 i tab2 doesn't starts onCreateView() or even onResume().
The interesting thing for me is that if i go to tab4 and then return to tab2, my data is in my spinner properly, so somehow swiping two tabs away from my current tab refreshing my fragment.
my question is how can i achieve proper refresh to my fragment when onCreateView() is called only once ?
Edit
i tried to put that method psykhi suggested like that:
this.mViewPager.setOffscreenPageLimit(0);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
but it's not working for me. Am i missing something ?
The best way that I have discovered to simulate a "setOffscreenPageLimit(0)" behavior is by using an OnPageChangeListener in conjunction with overriding the getItemPosition method in your adapter. Something like this:
In your custom pager adapter:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Then in your Activity containing the ViewPager:
final MyPagerAdapter adapter = new MyPagerAdapter();
pager.setAdapter(adapter);
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
... anything you may need to do to handle pager state ...
adapter.notifyDataSetChanged(); //this line will force all pages to be loaded fresh when changing between fragments
}
}
This should have the same effect as setting the OffscreenPageLimit to 0. However, this functionality is sort of against what the ViewPager is designed to provide. If you are trying to implement a ViewPager in this way, it may be worth reevaluating your layout to be sure that a ViewPager is really what you want to use.
UPDATE: There is a better way, Please have a look here: Update ViewPager dynamically?
Removing content of this answer because it was a really bad way to access Fragments inside ViewPager, please see the above link for better approach.
It's because you can specify the number of fragment your viewpager will "keep in RAM" (setOffScreenPageLimit () :I think the default is 1). So your second fragment is not reloaded. And when you go to a tab 3 or 4, then your 2 firsts fragments are deleted, then recreated when you come back.
To refresh your fragment, there is many way to do it: you could implement a listener interface of your own in it to tell it when to refresh, or simply call a method that you would implement to update your contents.
first override in the fragment method
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();//call the method to be refreshed
}
else{
//no
}
}
In my experience, ViewPagers keep:
Your current tab
& 1 tab either side in memory
So when you switch between 1 and 2, nothing is happening under the hood - it's like they are simply being hidden / shown.
But when you navigate to tab 4, tabs 1 & 2 are destroyed (onDestroy() called), so when you navigate back to either of them, they are being re-created fresh (onCreate() called).
As psykhi suggests, you could setOffScreenPageLimit() to 0, so that each fragment is created every time you navigate to it.
If you were interested in keeping the other pages in memory for performance purposes, as they were designed with this is mind, you could use a messaging/event publishing system to send a message from tab 1 to tab 2 telling it to update when you submit the form on tab 1.
Ok may be a late reply,might help others in future, so recently I faced same issue while fetching data from db into tabs it used to display only once I click on 3rd tab.. I tried above mentioned solution but nothing really worked.. fianlly i came across Otto
This library allows you to communicate within your app..
Just use this library to yourAdapter.notifyDataSetChanged() wherever you fetching your data from db..
This video helped me alot https://www.youtube.com/watch?v=lVqBmGK3VuA

ViewPager + FragmentStatePagerAdapter : need to know when fragment is displayed (selected)

I am using a ViewPager plugged to a FragmentStatePagerAdapter. Each fragment contains a listview. In this listview I wish to display ads and make calls to a analytics server. I only want to make those calls when the user navigates to a fragment (so I cannot use the onCreateView or onActivityCreated events in the Fragment). Is there an event I can hook on to this end ?
Update
I realized that the way I am fetching my current fragment is flawe
#Override
public void onPageSelected(int page) {
this.currentPage = page;
tabsAdapter.getItem(page);
}
getItem(int position) in the pager is actually responsible for instanciating the fragments, so it would create a new unattached fragment (hence getActivity() returning null). I think I will us an approach where I keep a map of the fragments (<Position, Fragment>), i will remove the fragment from the map when destoryItem is called in the pagerAdapter.
You are right, best option is the second solution here:
http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html
so your thoughts are correct.
How about this:
http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html
The onPageSelected(int) method sounds like it does what you want.

android fragments in different tabs

I'm building an app that the interface is based on this http://code.google.com/p/android-playground/, and I need to have a fragment inside of each tab (that are fragments). The tabs are all inflated from the same xml, and in that xml I have a fragment tag.
The problem is that when the activity is created, as the id of each fragment in the tabs are equal, the contents that should go to the second tab, go in the first.
I'm using this code to replace the fragment in the tab
FragmentTransaction ft = x.getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
I don't know if is possible to correct this.
do you want all the tabs to have the exactly the same content?
Usually when putting fragments in tabs each tab would be showing differnt content, so a xml file per tab would not be uncommon. You can have a seperate xml layout for each tab that just declares your fragment with a different id each time. Without declaring a seperate (read unique) id for each fragment there is no efficent / simple operation i know to get a handle to a specific fragment (as the id is the unique handle).
You also may be able to use a FragmentPagerAdapter depending on your needs. You could then fade your current tab fragment out, then call public void notifyDataSetChanged () and provide a new fragment. This is not really the standard way of doing it though and will not be preserved on the back stack.
Optionally you could create each tab programatically in the PagerAdapter and set a tag for each fragment when calling FragmentTransaction.add(..) and then use this tab-unique tag in future fragment transactions Ignore this, it does not look like you can switch fragements with a tag, id only im afraid. Go with my first suggestion I would!
I've struggled with ths as well and the way I reference a Fragment from its Activity later on is by accessing the Adapter for the tabs.
Assuming you use an Adapter, you could do something like this
private mTabsAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// etc
this.mTabsAdapter = new TabsAdapter(this, this.mViewPager);
// Tab1
Tab tab = actionBar.newTab();
this.mTabsAdapter.addTab(tab, MyFragment1.class, null);
// Tab2
tab = actionBar.newTab();
this.mTabsAdapter.addTab(tab, MyFragment2.class, null);
}
public MyFragment1 getTab1() {
return (MyFragment1)this.mTabsAdapter.getItem(0);
}
public MyFragment2 getTab2() {
return (MyFragment2)this.mTabsAdapter.getItem(1);
}
Then inside your fragment, you would have a method to access
public class MyFragment1 {
// ...
public void reloadData() {
// reload data here
}
}
Now you can access the Fragment such as
this.getTab1.reloadData();
This feels like a sad way to access a fragment, but you can't rely on a Tag in every scenario. Also, you must take care to only reference this where the reference to the Fragment exists.
There may be times that this will be null. For example if you nave a bunch of tabs, they may become garbage collected at some point. you should communicate between Fragments via a callback. This example is for only a few scenarios.
The callback method is described at Communicating with the Activity and I'd suggest this method if it fits your application. This will prevent the need for directly accessing tabs in most cases.

How to restore Android fragment view state

I have application titles fragment and contents fragment on the screen. When the user clicks on the item in titles fragment the according fragment is created and inserted to a frame and the selected title is highlighted in titles fragment.
Transaction is done with fragment.addToBackStack(), so when the user clicks the BACK key, the previous fragment is restored and inserted in the frame.
What is the best solution to restore view state when transaction manager restores fragments?
The problem is that I should highlight previous fragment name in titles fragment and I should know what fragment it is. I resolved it by storing view state in my own stack: when fragment is created and restoring on changing transaction backstack using transaction manager listener.
But this doesn't seem like the correct solution.
Before the answer, next time remember to add your code. Chances are my answer will not help you as much as it could because I don't really know your code.
This is old but anyway, IF I understand your question (and app architecture) correctly, it sounds like a case for interfacing.
Example:
add this interface as a member to the content fragment:
public class ContentFragment extends Fragment{
public interface onFragmentTitleHighlighted{
public void highLightTitle(String title);
}
}
and have the title fragment implement it. Make sure to equip your content fragments with the title fragmnet, and add a call to highLightTitle(String title); in the content fragment's onCreateView(...) call. This way whenever a new content fragmnet is being added the title will be highlighted.

Categories

Resources