Обновление TextView в ViewPager из другого фрагмента

Я пытаюсь обновить TextView во фрагменте, нажимая кнопку другого фрагмента.

На самом деле я реализовал функцию обратного вызова в Activity, и она работает, так как Logcat сообщает, что текст в TextView был изменен. Проблема в том, что Textview, показанный в первом фрагменте, не обновляется до нового значения! Это как фрагмент должен быть обновлен или что-то ...

Вот код активности ActionBarTabsPager:

import java.util.ArrayList;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ActionBar.Tab;
import android.support.v4.app.SupportActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;

/**
 * Demonstrates combining the action bar with a ViewPager to implement a tab UI
 * that switches between tabs and also allows the user to perform horizontal
 * flicks to move between the tabs.
 */
public class ActionBarTabsPager extends FragmentActivity implements SecondFragment.OnButtonClickedXListener{
    ViewPager  mViewPager;
    TabsAdapter mTabsAdapter;
    FragmentManager fm;



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

        setContentView(R.layout.actionbar_tabs_pager);



        if (savedInstanceState == null) {
             Fragment newFragment = new FirstFragment();
             FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
             ft.add(R.id.abs__custom, newFragment, "FirstFragment").commit();

             Fragment newFragment2 = new FirstFragment();
             FragmentTransaction ft2 = getSupportFragmentManager().beginTransaction();
             ft2.add(R.id.abs__custom, newFragment2, "SecondFragment").commit();
        }
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Fragment 1");
        ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Fragment 2");
        //ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Fragment 1");
        //ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Fragment 2");

        mViewPager = (ViewPager)findViewById(R.id.pager);
        mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);

            mTabsAdapter.addTab(tab1, FirstFragment.class);
            mTabsAdapter.addTab(tab2, SecondFragment.class);//LoaderCursorSupport.CursorLoaderListFragment.class);
            //mTabsAdapter.addTab(tab3, FirstFragment.class);//LoaderCustomSupport.AppListFragment.class);
            //mTabsAdapter.addTab(tab4, SecondFragment.class);//LoaderThrottleSupport.ThrottledLoaderListFragment.class);


        if (savedInstanceState != null) {
            getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
        }



    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("index", getSupportActionBar().getSelectedNavigationIndex());
    }

    /**
     * This is a helper class that implements the management of tabs and all
     * details of connecting a ViewPager with associated TabHost.  It relies on a
     * trick.  Normally a tab host has a simple API for supplying a View or
     * Intent that each tab will show.  This is not sufficient for switching
     * between pages.  So instead we make the content part of the tab host
     * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
     * view to show as the tab content.  It listens to changes in tabs, and takes
     * care of switch to the correct paged in the ViewPager whenever the selected
     * tab changes.
     */
    public class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<String> mTabs = new ArrayList<String>();

        public TabsAdapter(FragmentActivity activity, ActionBar actionBar, ViewPager pager) {
            super(activity.getSupportFragmentManager());
            mContext = activity;
            mActionBar = actionBar;
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);
        }

        public void addTab(ActionBar.Tab tab, Class<?> clss) {
            mTabs.add(clss.getName());
            mActionBar.addTab(tab.setTabListener(this));
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mTabs.size();
        }

        @Override
        public Fragment getItem(int position) {
            return Fragment.instantiate(mContext, mTabs.get(position), null);
        }


        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            mActionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            mViewPager.setCurrentItem(tab.getPosition());

        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        }
    }

    @Override
    public void OnButtonClickedX(View v) {

        if (v==findViewById(R.id.button1)){
            Log.i("TRIGGERED","TRIGGERED");

            FirstFragment ff = (FirstFragment) getSupportFragmentManager().findFragmentByTag("FirstFragment");

            View root = ff.getView();
            TextView tv = (TextView) root.findViewById(R.id.textView1);
            Log.i("Text before Edit",""+tv.getText());
            tv.setText("MODIFIED");
            Log.i("Text after Edit",""+tv.getText());




        }
        // TODO Auto-generated method stub

    }





}

FirstFragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FirstFragment extends Fragment {
    int mNum;


    /**
     * Create a new instance of FirstFragment, providing "num"
     * as an argument.
     */
    static FirstFragment newInstance(int num) {

        FirstFragment f = new FirstFragment();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putInt("num", num);
        f.setArguments(args);

        return f;
    }

    /**
     * When creating, retrieve this instance's number from its arguments.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNum = getArguments() != null ? getArguments().getInt("num") : 1;
    }

    /**
     * The Fragment's UI is just a simple text view showing its
     * instance number.
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.myfrag1, container, false);
        return v;
    }




}

SecondFragment:

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.SupportActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;

public  class SecondFragment extends Fragment {
    int mNum;
    OnButtonClickedXListener mListener;

    /**
     * Create a new instance of CountingFragment, providing "num"
     * as an argument.
     */
    static SecondFragment newInstance(int num) {
        SecondFragment f = new SecondFragment();

        // Supply num input as an argument.
        Bundle args = new Bundle();
        args.putInt("num", num);
        f.setArguments(args);

        return f;
    }

    /**
     * When creating, retrieve this instance's number from its arguments.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mNum = getArguments() != null ? getArguments().getInt("num") : 1;
    }

    /**
     * The Fragment's UI is just a simple text view showing its
     * instance number.
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.myfrag2, container, false);
        View button1 = v.findViewById(R.id.button1);
        button1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mListener.OnButtonClickedX(v);
                // TODO Auto-generated method stub

            }
        });



        return v;
    }

    public interface OnButtonClickedXListener{
        public void OnButtonClickedX(View v);
    }

    @Override
    public void onAttach(SupportActivity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);
        try {
            mListener = (OnButtonClickedXListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnButtonClickedXListener");
        }
    }

}

myfrag1.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >



    <TextView
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:text="No String"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

myfrag2.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="Button" />

</LinearLayout>

РЕДАКТИРОВАТЬ:

Даже если установить значение 0 на ContainerViewId в ft.add (), это никак не повлияет на окончательный рендеринг. Так что я думаю, что рендеринг управляется

mTabsAdapter.addTab(tab1, FirstFragment.class);
mTabsAdapter.addTab(tab2, SecondFragment.class);

Во всяком случае, проблема остается прежней.

Вотactionbar_tabs_pager.xml

<?xml version="1.0" encoding="utf-8"?>

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>

Ответы на вопрос(4)

РЕШИТЬ!

ПереопределениеinstantiateItem () в TabsAdapter и добавление ViewPager в качестве ContainerViewID в FragmentTransaction сделало это!

Вот и весь функционал FragmentActivity!

import java.util.ArrayList;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ActionBar.Tab;
import android.support.v4.app.SupportActivity;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;

/**
 * Demonstrates combining the action bar with a ViewPager to implement a tab UI
 * that switches between tabs and also allows the user to perform horizontal
 * flicks to move between the tabs.
 */
public class ActionBarTabsPager extends FragmentActivity implements SecondFragment.OnButtonClickedXListener{
    ViewPager  mViewPager;
    TabsAdapter mTabsAdapter;
    FragmentManager fm;



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

        Log.i("ONCREATE START","ONCREATE START");


        setContentView(R.layout.actionbar_tabs_pager);


        if (savedInstanceState == null) {


            Fragment newFragment = new FirstFragment();
            Fragment newFragment2 = new SecondFragment();

            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.add(R.id.pager, newFragment, "FirstFragment");
            ft.add(R.id.pager, newFragment2, "SecondFragment");
            ft.commit();


       }

        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Fragment 1");
        ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Fragment 2");
        //ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Fragment 1");
        //ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Fragment 2");

        mViewPager = (ViewPager)findViewById(R.id.pager);
        mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);

            mTabsAdapter.addTab(tab1, FirstFragment.class);
            mTabsAdapter.addTab(tab2, SecondFragment.class);//LoaderCursorSupport.CursorLoaderListFragment.class);
            //mTabsAdapter.addTab(tab3, FirstFragment.class);//LoaderCustomSupport.AppListFragment.class);
            //mTabsAdapter.addTab(tab4, SecondFragment.class);//LoaderThrottleSupport.ThrottledLoaderListFragment.class);



        if (savedInstanceState != null) {
            getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
        }

        Log.i("ONCREATE END","ONCREATE END");

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        Log.i("onSaveInstanceState START","onSaveInstanceState START");
        super.onSaveInstanceState(outState);
        outState.putInt("index", getSupportActionBar().getSelectedNavigationIndex());
        Log.i("onSaveInstanceState END","onSaveInstanceState END");

    }

    /**
     * This is a helper class that implements the management of tabs and all
     * details of connecting a ViewPager with associated TabHost.  It relies on a
     * trick.  Normally a tab host has a simple API for supplying a View or
     * Intent that each tab will show.  This is not sufficient for switching
     * between pages.  So instead we make the content part of the tab host
     * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
     * view to show as the tab content.  It listens to changes in tabs, and takes
     * care of switch to the correct paged in the ViewPager whenever the selected
     * tab changes.
     */
    public class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<String> mTabs = new ArrayList<String>();
        private FragmentTransaction mCurTransaction = null;


        public TabsAdapter(FragmentActivity activity, ActionBar actionBar, ViewPager pager) {
            super(activity.getSupportFragmentManager());
            mContext = activity;
            mActionBar = actionBar;
            mViewPager = pager;
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(this);


        }

        public void addTab(ActionBar.Tab tab, Class<?> clss) {
            Log.i("addTab","addTab");

            mTabs.add(clss.getName());
            mActionBar.addTab(tab.setTabListener(this));
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mTabs.size();
        }

        @Override
        public Object instantiateItem(View container, int position) {
            if (mCurTransaction == null) {
                mCurTransaction = getSupportFragmentManager().beginTransaction();
            }
            // TODO Auto-generated method stub
            Fragment fragment = getItem(position);

            if (fragment!=null){
                Log.i("Fragment Found!","Fragment Found! "+fragment.getTag());
                mCurTransaction.attach(fragment);
                }


            return fragment;//super.instantiateItem(container, position);
        }

        @Override
        public Fragment getItem(int position) {
            Log.i("getItem","getItem");

            if (position==0)
                {Log.i("position=0","position=0");
                return getSupportFragmentManager().findFragmentByTag("FirstFragment");}

            else if (position==1)
            {Log.i("position=1","position=1");
                return getSupportFragmentManager().findFragmentByTag("SecondFragment");}

            else return null;//Fragment.instantiate(mContext, mTabs.get(position), null);

        }


        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            mActionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            mViewPager.setCurrentItem(tab.getPosition());

        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        }


    }

    @Override
    public void OnButtonClickedX(View v) {

        if (v==findViewById(R.id.button1)){
            Log.i("TRIGGERED","TRIGGERED");

            FirstFragment ff = (FirstFragment) getSupportFragmentManager().findFragmentByTag("FirstFragment");

            View root = ff.getView();
            TextView tv = (TextView) root.findViewById(R.id.textView1);
            Log.i("Text before Edit",""+tv.getText());
                  tv.setText("MODIFIED");
                  Log.i("Text after Edit",""+tv.getText());




        }
        // TODO Auto-generated method stub

    }





}

Спасибо vbsteven!

что это случай «перекрывающихся» фрагментов - не редкость для тех, кто впервые пробует фрагменты. Каждый раз, когда вы повторно отображаете фрагмент (отобразите фрагмент, покажите другой, затем вернитесь к первому отображенному фрагменту), вы создаете новый фрагмент за видимым фрагментом. «Зеркальный фрагмент» остается сверху, блокируя ваш взгляд на фрагмент позади него. Только прокручивая этот фрагмент, вы увидите, что фрагмент позади действительно обновляется.

В большинстве случаев это просто случай, когда вы повторяете то, что вы делали в XML, в своей FragmentActivity. Опубликуйте свой макет XML, чтобы профессионалы по фрагментам могли лучше диагностировать вашу проблему.

 Mariux05 февр. 2012 г., 21:03
Я не думаю, что это проблема макета, так как фрагменты не объявлены в xml, все они добавлены из источника ... возможно, что-то есть в TabsAdapter, но я не могу понять это ...

что фрагменты, которые вы видите на экране, - это не фрагменты, которые вы добавляете вручную с тегами «FirstFragment» и «SecondFragment», а фрагменты, которые добавляются методом getItem вашего TabsAdapter.

Если вы посмотрите на его реализацию, он создает новые фрагменты.

    @Override
    public Fragment getItem(int position) {
        return Fragment.instantiate(mContext, mTabs.get(position), null);
    }

Эти вновь созданные фрагменты добавляются в FragmentManager с помощью пользовательских тегов, созданных в FragmentPagerAdapter (который расширяет TabsAdapter).

 Mariux09 февр. 2012 г., 14:49
Я закомментировал FragmentTransaction, и фактически интерфейс создан правильно. Так что, вероятно, getItem () вызывается, когда mTabsAdapter.addTab (tab1, FirstFragment.class); mTabsAdapter.addTab (tab2, SecondFragment.class); называется. Так как же мне вернуть экземпляр FirstFragment и SecondFragment без повторного создания экземпляра?
 vbsteven09 февр. 2012 г., 14:54
Вам придется переопределить методы instantiateItem / getItem, чтобы они использовали ваши фрагменты вместо создания новых. Вероятно, вам лучше создать новый подкласс PagerAdapter (посмотрите на источник FragmentPagerAdapter для справки), который учитывает существующие фрагменты.
 Mariux09 февр. 2012 г., 16:14
Есть ли пример или приложение с исходным кодом, чтобы понять это?

Не знаю, решит ли это ваши проблемы, но в этой части кода вы добавляете FirstFragment () для обоих фрагментов ...

Fragment newFragment = new FirstFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.abs__custom, newFragment, "FirstFragment").commit();

Fragment newFragment2 = new FirstFragment();
FragmentTransaction ft2 = getSupportFragmentManager().beginTransaction();
ft2.add(R.id.abs__custom, newFragment2, "SecondFragment").commit();

... и вы могли бы написать это более просто так:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.abs__custom, newFragment, "FirstFragment");
ft.add(R.id.,abs__custom, newFragment2, "SecondFragment");
ft.commit();
 Mariux09 февр. 2012 г., 11:37
R.id.abs__custom.xml не имеет значения, пожалуйста, посмотрите на изменения!
 ramdroid07 февр. 2012 г., 13:29
И где в xml вы определили "R.id.abs__custom"?
 Mariux06 февр. 2012 г., 17:12
Это не решает проблему, однако спасибо за указание на это. оказалось, что даже присвоение «0» функции ft.add () для макета, как в «ft.add (0, newFragment,« FirstFragment »); ' не влияет на рендеринг. Я думаю, «mTabsAdapter.addTab (tab1, FirstFragment.class);» это то, что отображает макет, а не транзакцию.

Ваш ответ на вопрос