安卓:从ViewPager / FragmentStatePagerAdapter获取参考片段 [英] Android: Get Fragment Reference from ViewPager/FragmentStatePagerAdapter

查看:253
本文介绍了安卓:从ViewPager / FragmentStatePagerAdapter获取参考片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

披露了前面,这是一所学校的项目。

Disclosure up front, this is a school project.

我一直在由一系列动态操作栏标签和列表碎片的项目活动,并一直停留在获取对象引用的特定标签片段,以设置适配器的前景该列表视图。

I've been working on an activity in a project that consists of a series of dynamic action bar tabs and list fragments, and have been stuck on the prospect of getting object references to the specific tab fragments in order to set adapters for the list views.

我有它设置为使用ViewPager(支持V4版本)和FragmentStatePagerAdapter(V13)的时刻。我试过在几个提到SO质疑线程,方法即这三种:

I have it set up at the moment using a ViewPager (the support v4 version) and a FragmentStatePagerAdapter (v13). I've tried methods mentioned in a few SO question threads, namely these three:

<一个href=\"http://stackoverflow.com/questions/16372875/updating-fragments-views-in-viewpager-with-fragmentstatepageradapter\"标题=更新片段/与fragmentStatePagerAdapter viewpager意见中viewpager>更新片段/意见与fragmentStatePagerAdapter

从中检索ViewPager 一个片段

<一个href=\"http://stackoverflow.com/questions/10849552/android-viewpager-cant-update-dynamically?lq=1\">Android ViewPager - 无法更新动态

然而,这些尝试都已经无济于事,这里是从我的尝试,试图证明什么,我试图完成相关code。

However, each of these attempts have been to no avail, here is the relevant code from my attempt to try and demonstrate what I'm trying to accomplish.

的code为FragmentStatePagerAdapter:

    /**
 * The Class ServerPagerAdapter.
 */
private class ServerPagerAdapter extends FragmentStatePagerAdapter
{
    SparseArray<ServerViewFragment> registeredFragments = new SparseArray<ServerViewFragment>();


    /**
     * Instantiates a new server pager adapter.
     *
     * @param fm the fragment manager
     */
    public ServerPagerAdapter(FragmentManager fm)
    {
        super(fm);
    }

    /* (non-Javadoc)
     * @see android.support.v13.app.FragmentPagerAdapter#getItem(int)
     */
    @Override
    public Fragment getItem(int position)
    {
        ServerViewFragment serverFrag = new ServerViewFragment();
        registeredFragments.put(position, serverFrag);

        return serverFrag;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) 
    {
        super.destroyItem(container, position, object);
        registeredFragments.remove(position);
    }


    /* (non-Javadoc)
     * @see android.support.v4.view.PagerAdapter#getCount()
     */
    @Override
    public int getCount()
    {
        // TODO STATIC VALUE.
        return 3;
    }



    /* (non-Javadoc)
     * @see android.support.v4.view.PagerAdapter#getPageTitle(int)
     */
    @Override
    public CharSequence getPageTitle(int position)
    {
        //TODO: HARD CODED
        switch (position)
        {
            case 0:
                return "Status";
            case 1:
                return "#chat";
            case 2:
                return "#help";
        }
        return null;
    }

    public ServerViewFragment getFragment(int position)
    {
        return registeredFragments.get(position);
    }

}

活动中的code,我试图去工作:

    @Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_server_view);

            /*Code omitted (actionbar navigation)*/

    //connect pager
    servPagerAdapter = new ServerPagerAdapter(getFragmentManager());

    viewPager = (ViewPager)findViewById(R.id.server_view_pager);
    viewPager.setAdapter(servPagerAdapter);
    viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
    {
        @Override
        public void onPageSelected(int position)
        {
            actionBar.setSelectedNavigationItem(position);
        }
    });

    //populate tabs
    for (int i = 0; i < servPagerAdapter.getCount(); i++)
    {
        Tab tabToAdd = actionBar.newTab();
        tabToAdd.setText(servPagerAdapter.getPageTitle(i));
        tabToAdd.setTabListener(this);
        actionBar.addTab(tabToAdd);
    }

    svf = servPagerAdapter.getFragment(0);
    csvf = servPagerAdapter.getFragment(1);

    IRCConnection testConn = new IRCConnection();
    testConn.setOnIRCMessageReceivedListener(this);

            //adapters are populated in a separate method
    adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
    cadapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);

    Log.i("ADAPTER", adapter == null ? "Null" : "Not Null");
    Log.i("FRAGMENT", svf == null ? "Null" : "Not Null");


    //svf.setListAdapter(adapter);
    //csvf.setListAdapter(cadapter);

    /*code omitted (network call)*/

}

SVF和csvf是我使用只是尝试变量和测试得到它的工作,他们正在键入的ListFragment基于类是完全俗套。最后,我希望能够在他们每个人添加和删除适配器选项卡和管理列表视图。

svf and csvf are variables I'm using to just try and test getting it to work, they are typed of a ListFragment based class that is completely cookie cutter. Eventually I want to be able to add and remove tabs from the adapter and manage the listviews in each of them.

在这个阶段,它可能的我不理解的话题/路适配器工作的只是一个问题,我希望这只是一个基于无知的问题,这有一个简单的解决方案。

At this stage it's probably a just an issue of me not understanding the topic/way the adapter works, and I'm hoping this is just an ignorance based question, and that there's a simple solution.

编辑:我已经取得了一些进展,但在可见的选项卡上调用刷新抛出一个空指针出于某种原因。下面是从我的连接类的回调,回调是活动类中:

I've made some progress, but calling refresh on the visible tab is throwing a null pointer for some reason. Here's the callback from my connection class, the callback being inside the activity class:

    @Override
public void onNetworkMessageReceived(String message)
{
    final String msg = message;

    this.runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            FragmentData data = fragmentDataMapper.getData("Network");
            ServerViewFragment visFrag = servPagerAdapter.getFragment(getActionBar().getSelectedNavigationIndex());

            if (data == null)
            {

                ArrayList<String> chatStrings = new ArrayList<String>();
                chatStrings.add(msg);
                data = new FragmentData(chatStrings);
                visFrag.refresh(data);
                fragmentDataMapper.updateData("Network", data);
            }
            else
            {
                ArrayList<String> chatStrings = data.getChatStrings();
                chatStrings.add(msg);
                data = new FragmentData(chatStrings);
                visFrag.refresh(data);

                fragmentDataMapper.updateData("Network", data);
            }   
        }
    });

    Log.i("HANDLER", message);
}

该异常被抛出在任一visFrag.refresh线,因为visFrag为空。我仍然使用相同的registeredFragments的事情与以前。

The exception is being thrown on either of the visFrag.refresh lines, as visFrag is null. I'm still using the same registeredFragments thing from before.

推荐答案

由于最新的评论,我对你怎么或许可以得到你所寻求的行为的建议。

Given the latest comment, I have a suggestion of how you perhaps could get the behaviour you seek.

我相信,在活动中,标签和碎片您的设置是非常合情合理的。它是唯一一个需要解决的活性和片段之间的通信。

I believe that your setup with the activity, the tabs and the fragments makes perfect sense. It is only the communication between activity and fragment which needs to be addressed.

在我自己的项目中,我利用registeredFragments办法,但仅针对当前可见的片段,因为一个始终是非空。这是整齐更新当前可见的信息,但我想更新已被传递到另一个不同的片段,以保持稳定。

In my own project I make use of the registeredFragments approach but only for the currently visible fragment, as that one will always be non-null. This is neat to update the currently visible information but I think that the update has to be communicated to the other fragments differently in order to be stable.

我不会解决的更新是如何在您的设置做了具体而言,我不知道如何以及何时处理当前这一点,所以这将是一个有点一般。

I will not address how the update is done in your setting specifically, as I do not know how and when you currently handle this, so this will be a bit general.

好了,这里是我的建议:

Ok, so here is my suggestion:

简单得持有片段,并要显示的信息之间的映射一个静态类。这种映射可以是唯一的名称或给每个片段的应该显示的信息的模型的页面编号之间。这个想法在这里这里概述:

Simply have a static class which holds a mapping between fragments and the information you want to show. This mapping could be between a unique name or a pagenumber given to each fragment to a model of the information it should display. The idea is outlined here here:

public class FragmentDataMapping {
    // FragmentId could be anything like String or Integer
    private Map<FragmentId, FragmentData> fragmentData = new HashMap<>();

    public static void updateData(FragmentId fragmentId, FragmentData fragmentData) {
        fragmentData.put(fragmentId, fragmentData);
    }

    public static FragmentData getData(FragmentId fragmentId) {
        return fragmentData.get(fragmentId);
    }
}

// FragmentData could be any kind of model object for your fragments
public class FragmentData {
    private String someData;
    private Integer someOtherData;
    private... and so on

    // constructor, setter and getter methods
}

使用某种映射和数据模型这样的,你现在可以在您的活动,只要你从服务器获取数据,创建一个信息FragmentData对象,并将其与关联的片段。

Using some sort of Mapping and Model data like this, you can now in your activity, as soon as you get data from the server, create a FragmentData object with the information and associate it with a fragment.

public void serverResponse(String someData, Integer someOtherData) {
    FragmentData newData = new FragmentData(someData, someOtherData);
    FragmentDataMapping.updateData("DetailsFragment", newData);
}

而在你的碎片onResume,你会检查FragmentData获得的最新数据。

And in onResume of your fragments, you would inspect the FragmentData to get the most recent data.

// This is inside DetailsFragment
private String fragmentId = "DetailsFragment"; // <- some id assigned at creation

public void onResume() {
    FragmentData data = FragmentDataMapping.getData("DetailsFragment");
    Log.d("DetailsFragment", "My data: " + data.getSomeData() + " and " + data.getSomeOtherData());
    refresh(fragmentData)
    ....
}

public void refresh(FragmentData fragmentData) {
   // set adapters, update view or do whatever with the data.
   // the reason for creating a seperate method to handle the fragmentData follows below
}

通过这个(或像这样),碎片将尽快作为一个新的选项卡被选中更新数据。

With this (or something like this), the fragments will update the data as soon as a new tab gets selected.

现在,当前可见的碎片本身不会用这种方法为onResume()被称为未更新。因此,更新当前片段,您可以使用您的viewpager的registeredFragments:

Now, the currently visible fragment would not update itself with this method as onResume() is not called. Therefore, to update the current fragment you can use the registeredFragments of your viewpager:

public void serverResponse(String someData, Integer someOtherData) {
    FragmentData newData = new FragmentData(someData, someOtherData);
    FragmentDataMapping.updateData("DetailsFragment", newData);
    registeredFragments(getActionBar().getSelectedNavigationIndex()).refresh(newData);
}

我知道实现的描述是模糊的,但我希望它有一些想法,而且你可以从调查中获​​益的一些要点。

I know this description of an implementation is vague but I hope it has some ideas and some points that you can benefit from investigating.

这篇关于安卓:从ViewPager / FragmentStatePagerAdapter获取参考片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆