在Activity中访问Fragment?

5

我有一个主要活动和两个片段。这两个片段都有一个 ListView。我想在 MainActivity 中更新列表。有没有一种方法可以在不将适配器作为静态适配器的情况下,在活动中访问片段列表适配器。 目前我在 Mainactivity.java 中执行以下操作:

public void updatelist() {
  if(fragmentstate=0)
    Fragment1.adapter.notifyDataSetChanged();
  else
    Fragment2.adapter.notifyDataSetChanged();

}

可能是重复的问题:如何从FragmentActivity获取片段实例? - Sipty
@Spity,它怎么会成为片段实例的副本。即使我在代码中使用了单例模式来管理片段,但适配器还是出现了问题。 - Asthme
4个回答

5
你可以使用Otto事件总线来完成以下操作:
public class UpdateListEvent {
    private int fragmentState;

    public UpdateListEvent(int fragmentState) {
        this.fragmentState = fragmentState;
    }
}

public class MainActivity extends ActionBarActivity {
    ...
    public void updatelist() {
       SingletonBus.INSTANCE.getBus().post(new UpdateListEvent(fragmentState));
    }
}

public class FragmentA extends Fragment {
    @Override
    public void onResume() {
        super.onResume();
        SingletonBus.INSTANCE.getBus().register(this);
    }

    @Override
    public void onPause() {
        SingletonBus.INSTANCE.getBus().unregister(this);
        super.onPause();
    }

    @Subscribe
    public void onUpdateListEvent(UpdateListEvent e) {
        if(e.getFragmentState() == 0) { //is this even necessary?
            this.adapter.notifyDataSetChanged();
        }
    }
}

public class FragmentB extends Fragment {
    @Override
    public void onResume() {
        super.onResume();
        SingletonBus.INSTANCE.getBus().register(this);
    }

    @Override
    public void onPause() {
        SingletonBus.INSTANCE.getBus().unregister(this);
        super.onPause();
    }

    @Subscribe
    public void onUpdateListEvent(UpdateListEvent e) {
        if(e.getFragmentState() != 0) { //is this even necessary?
             this.adapter.notifyDataSetChanged();
        }
    }
}

还有经过改进的单例总线

public enum SingletonBus {
    INSTANCE;

    private static String TAG = SingletonBus.class.getSimpleName();

    private Bus bus;

    private volatile boolean paused;

    private final Vector<Object> eventQueueBuffer = new Vector<>();

    private Handler handler = new Handler(Looper.getMainLooper());

    private SingletonBus() {
        this.bus = new Bus(ThreadEnforcer.ANY);
    }

    public <T> void postToSameThread(final T event) {
        bus.post(event);
    }

    public <T> void postToMainThread(final T event) {
        try {
            if(paused) {
                eventQueueBuffer.add(event);
            } else {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            bus.post(event);
                        } catch(Exception e) {
                            Log.e(TAG, "POST TO MAIN THREAD: BUS LEVEL");
                            throw e;
                        }
                    }
                });
            }
        } catch(Exception e) {
            Log.e(TAG, "POST TO MAIN THREAD: HANDLER LEVEL");
            throw e;
        }
    }

    public <T> void register(T subscriber) {
        bus.register(subscriber);
    }

    public <T> void unregister(T subscriber) {
        bus.unregister(subscriber);
    }

    public boolean isPaused() {
        return paused;
    }

    public void setPaused(boolean paused) {
        this.paused = paused;
        if(!paused) {
            Iterator<Object> eventIterator = eventQueueBuffer.iterator();
            while(eventIterator.hasNext()) {
                Object event = eventIterator.next();
                postToMainThread(event);
                eventIterator.remove();
            }
        }
    }
}

但如果这只是跟踪当前活动片段的问题,那么这就过度了。或者至少,fragmentState是否必要?我认为不是。毕竟,只有活动的片段才会接收到事件。 - EpicPandaForce
我希望我能使用Otto,但我不能。 - Asthme
1
哦,那太糟糕了。LocalBroadcastManager可以作为穷人版的Otto。 - EpicPandaForce
请注意,Otto 在您发布事件的同一线程上交付事件 - EpicPandaForce
onPause()中调用setPaused(true),并在onPostCreate()中调用setPaused(false) - EpicPandaForce

1
不要使用静态适配器。有更好(更安全)的方法可以从父Activity中访问你的片段。
我假设你是通过使用类似于这样的方式动态添加你的片段的:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager
              .beginTransaction()
              .add(R.id.fragment_container, new FragmentOne())
              .commit();

And same for fragment two.
为了引用这些Fragment,您需要在创建它们时添加一个标签。非常简单,只需在现有代码中添加一行即可:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager
              .beginTransaction()
              .add(R.id.fragment_container, new FragmentOne(), "fragmentOneTag")
              .commit();

然后,每当您想获取片段时,请执行以下操作:

FragmentManager fragmentManager = getFragmentManager();
FragmentOne fragmentOne = fragmentManager.getFragmentByTag("fragmentOneTag");

fragmentOne.refreshList();      //Define this method in your class and from there refresh your list

就是这样


我想知道使用 getFragmentByTag("fragmentOneTag") 是否比使用 static 访问适配器对性能影响更大。 - hrskrs
1
refreshList() 不是静态的。getFragmentByTag 返回所请求的片段的引用,因此您可以访问它的公共方法。 - Carlos J

1
如果您只想更新片段上的列表,您不必访问适配器。您可以在片段上注册本地广播,并从MainActivity发送本地广播消息。
从片段开始,
LocalBroadcastManager.getInstance(getContext()).registerReceiver(...);

从MainActivity开始,

LocalBroadcastManager.getInstance(getContext()).sendBroadcast(...)

为什么要这样做?所有的Fragments都必须附加到创建并添加FragmentsActivity上。Activity所需做的就是在相关的Fragment引用上调用一个public方法。 - Squonk
@Benrad Kim,你说得对。所有东西都进入一个单一的活动。那我为什么要广播呢? - Asthme

0
有没有办法在不将适配器作为静态适配器的情况下,在活动中访问片段列表适配器。
是的。设计指南允许片段公开可以从它们附加到的活动中调用的public方法。只需在每个片段中创建一个方法,并调用您需要的任何一个方法即可。 活动应该持有对其创建的任何片段的引用。只需让片段方法更新自己的适配器即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接