11

I want to periodically update a fragment's display based on data I download from the Internet. I have created a Timer and Runnable to periodically retrieve this data as well as a method within the fragment to update it, but I cannot seem to figure out how to gain a reference from the activity to the fragment in order to update it.

I have the following code which was mostly generated by the ADT's Android Project wizard:

    protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);

    Log.d(tag, "onCreate()::Entering...");

    setContentView(R.layout.activity_main);

    // Set up the action bar.
    final ActionBar actionBar = getSupportActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // Create the adapter that will return a fragment for each of the
    // primary sections of the activity.
    mSectionsPagerAdapter = new SectionsPagerAdapter(
            getSupportFragmentManager());

    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    // When swiping between different sections, select the corresponding
    // tab. We can also use ActionBar.Tab#select() to do this if we have
    // a reference to the Tab.
    mViewPager
            .setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    actionBar.setSelectedNavigationItem(position);
                }
            });

    // For each of the sections in the app, add a tab to the action bar.
    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) 
    {
        // Create a tab with text corresponding to the page title defined by
        // the adapter. Also specify this Activity object, which implements
        // the TabListener interface, as the callback (listener) for when
        // this tab is selected.
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(i))
                .setTabListener(this));
    }   

Here is the code used to create the tabs:

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) 
    {
        // getItem is called to instantiate the fragment for the given page.

        switch (position)
        {
        case FRAG1_POS:
            return Fragment1.newInstance();

        case FRAG2_POS:
            return Fragment2.newInstance(); 

        default:
            return null;
        }
    }

I have tried using this solution:

How to change fragment's textView's text from activity

But I don't have the fragment ID. Can I create tags? If so, how do I do that in this case? Other SO posts have mentioned Bundles but I am not sending data when creating the fragment; I want to have the fragment periodically updated as data becomes available from the Activity.

Community
  • 1
  • 1
gonzobrains
  • 7,856
  • 14
  • 81
  • 132

2 Answers2

8

You cannot give your fragments a tag or id but you can create a custom property on your fragment class to mark them.

switch (position)
    {
    case FRAG1_POS:
        Fragment1 f = Fragment1.newInstance();
        f.fragmentType = 1;
        return f;

    case FRAG2_POS:
        Fragment1 f = Fragment1.newInstance();
        f.fragmentType = 2;
        return f;

    default:
        return null;
    }

When can then loop through all the fragments and find the one you need

List<Fragment> allFragments = getSupportFragmentManager().getFragments();
if (allFragments != null) {
    for (Fragment fragment : allFragments) {
        Fragment1 f1 = (Fragment1)fragment;
        if (f1.fragmentType == 1)
            f1.updateFragmentData();
    }
}
}

Add a public method to your fragment that will update the data in your fragment. As you have a reference to it now, you can just call it from your activity.

Szymon
  • 42,577
  • 16
  • 96
  • 114
  • Given the way my fragments are created via GetItem(), how can I set their tags and retain them? – gonzobrains Mar 31 '14 at 01:06
  • Can you show the code where you create your fragments? – Szymon Mar 31 '14 at 01:07
  • Okay, I added it. It's pretty much what was created by the new project wizard. – gonzobrains Mar 31 '14 at 03:20
  • Right, you cannot add a tag but you can add a property that would act as a tag. Please see my update now. – Szymon Mar 31 '14 at 03:44
  • I was thinking of doing something like this before but the Fragments are not both of the same type. Would I have to use Reflection? – gonzobrains Mar 31 '14 at 04:08
  • 3
    No, that's even easier as you don't have to mark fragments in any way. Just check the type of each fragment in the loop: `if (fragment instanceof YourFragment)` – Szymon Mar 31 '14 at 04:11
  • This worked great! Is this the normal way to do this? If so, I wonder why there aren't more examples of how to do it this way. – gonzobrains Apr 01 '14 at 04:39
  • getFragments() method is not in the documentation but it works. Maybe that's why. – Szymon Apr 01 '14 at 04:42
  • I had seen getFragments() before, but it was using it with instanceof that really helped the most. What I don't understand is why this isn't more widely known. What is the "normal" way to update fragments from a timer-based Internet update? – gonzobrains Apr 01 '14 at 04:52
  • Not that sure what is "normal". There may not be such a thing :) – Szymon Apr 01 '14 at 04:54
  • 1
    Yeah, when I say "normal" I mean something that is more obvious through documentation, existing Google searches, etc. At least now if my question gets upvotes it will help others in this situation! :) – gonzobrains Apr 01 '14 at 05:24
  • @Szymon Can you please give me any solution for my issue.. http://stackoverflow.com/questions/30303488/how-to-update-fragments-data-used-in-viewpager-view-is-not-showing-the-updated – Arun Badole May 20 '15 at 11:00
  • It is not possible to use an attribute in the activity class with a reference to the fragment instance? – JCarlosR Aug 11 '16 at 20:11
  • This no longer works. `getFragments` can now only be called from within the same library group. Is there another way? – M3-n50 May 31 '18 at 10:20
2

Here is something you could try:

Since you mention updating the fragment from the activity (with retrieved data), you could do something like this:

In your Runnable or AsyncTask, you can update the adapter with the data retrieved and in your fragment, call the onDatasetChanged() method on the adapter so it will automatically update the view.

If you have multiple fragments, inside those fragments, you could define an interface and then let the activity implement it and then override the method. From within that method in the activity, update the adapter that holds the data. You will have to make the adapter static!

I hope this helps!

Eenvincible
  • 5,641
  • 2
  • 27
  • 46
  • I tried using onDatasetChanged(), but nothing happened. Is there a method I need to override in the Fragment classes that responds to this? If not, was is the connection I need to establish between the data and the retrieved data. I think I am missing something. – gonzobrains Mar 31 '14 at 03:38