在活动中访问片段?

Posted

技术标签:

【中文标题】在活动中访问片段?【英文标题】:Access Fragment in Activity? 【发布时间】:2015-04-13 09:06:38 【问题描述】:

我有一个包含 2 个片段的主要活动。两个片段都有一个ListView。我想更新MainActivity 中的列表。有没有办法在不将适配器设置为静态适配器的情况下访问活动中的片段列表适配器。 目前我在Mainactivity.java做这样的事情@

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


【问题讨论】:

How to get the fragment instance from the FragmentActivity? 的可能重复项 @Spity 它将如何与片段实例重复。即使我在片段的代码中使用单例。但适配器制作问题 【参考方案1】:

您可以使用 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 是否必要?我不这么认为。毕竟,片段只有在它们处于活动状态时才会收到事件。 我希望我可以使用 otto。但我不能。 哦。太糟糕了。 LocalBroadcastManager 可以作为穷人的奥托。 请注意,Otto您发布活动的同一线程上提供活动。 onPause() 中调用setPaused(true) 并在onPostCreate() 中调用setPaused(false)【参考方案2】:

不要使用静态适配器。有更好(更安全)的方法可以从它的父级 Activity 访问您的片段。

我假设您使用以下方式动态添加片段:

FragmentManager fragmentManager = getFragmentManager();
fragmentManager
              .beginTransaction()
              .add(R.id.fragment_container, new FragmentOne())
              .commit();

片段二也一样。

为了引用那些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访问适配器更影响性能 refreshList() 不是静态的。 getFragmentByTag 返回对请求片段的引用,以便您可以访问它的公共方法【参考方案3】:

如果您只想更新片段列表,则不必访问 adpaters。您可以在 Fragment 上注册本地广播,并从 MainActivity 发送本地广播消息。

来自片段,

LocalBroadcastManager.getInstance(getContext()).registerReceiver(...);

来自 MainActivity,

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

【讨论】:

你为什么要这样做?所有Fragments 必须附加到一个Activity,它首先创建并添加了Fragments。所有Activity 所要做的就是在相关的Fragment 引用上调用public 方法。 @Benrad Kim 你是对的。一切都进入单一活动。我为什么要广播?【参考方案4】:

有没有办法在不将适配器设置为静态适配器的情况下访问活动中的片段列表适配器。

是的。 Fragments 的设计指南允许他们公开public 方法,这些方法可以从他们所附加的Activity 中调用。只需在每个 Fragment 中创建一个方法,然后调用您需要的任何一个。

Activity 应该持有对其创建的任何Fragments 的引用。只需让 Fragment 方法更新它们自己的适配器即可。

【讨论】:

以上是关于在活动中访问片段?的主要内容,如果未能解决你的问题,请参考以下文章

如何访问活动内部/从活动中的片段视图组件

实现一个可以从每个片段和活动中访问的按钮

从片段访问父活动的数据

从活动访问片段的视图

Android:使用 putExtra 从片段访问容器活动对象?

通过 findById 访问活动布局中的硬编码片段