支持FragmentPagerAdapter持有引用旧片段 [英] support FragmentPagerAdapter holds reference to old fragments

查看:109
本文介绍了支持FragmentPagerAdapter持有引用旧片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最新信息:

我已经缩小我的问题到是与fragmentManager保留旧片段的实例,我viewpager不同步我的FragmentManager一个问题。看到这个问题... <一个href="http://$c$c.google.com/p/android/issues/detail?id=19211#makechanges">http://$c$c.google.com/p/android/issues/detail?id=19211#makechanges 。我仍然不知道如何解决这个问题。任何建议...

i have narrowed my problem down to being a problem with the fragmentManager retaining instances of old fragments and my viewpager being out of sync with my FragmentManager. See this issue... http://code.google.com/p/android/issues/detail?id=19211#makechanges . I still have no clue how to solve this. Any suggestions...

我试图调试这个相当长的时间,任何帮助将不胜AP preciated。我使用它接受像这样的片段列表的FragmentPagerAdapter:

I have tried to debug this for a long time and any help would be greatly appreciated. I am using a FragmentPagerAdapter which accepts a list of fragments like so:

List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName())); 
...
new PagerAdapter(getSupportFragmentManager(), fragments);

的实施标准。我使用ActionBarSherlock和V4可计算库片段。

The implementation is standard. I am using ActionBarSherlock and v4 computability library for Fragments.

我的问题是,让应用程序开放一些其他的应用程序和回来后,碎片失去其参考回到FragmentActivity(即 getActivity()== NULL )。我想不通为什么发生这种情况。我想手动设置 setRetainInstance(真); 但这并没有帮助。我想,出现这种情况时,我FragmentActivity被摧毁,然而这仍然发生,如果我打开应用程序之前,我得到的日志信息。有没有什么想法?

My problem is that after leaving the app and opening several other applications and coming back, the fragments lose their reference back to the FragmentActivity (ie. getActivity() == null). I can not figure out why this is happening. I tried to manually set setRetainInstance(true); but this does not help. I figured that this happens when my FragmentActivity gets destroyed, however this still happens if I open the app before I get the log message. Are there any ideas?

@Override
protected void onDestroy(){
    Log.w(TAG, "DESTROYDESTROYDESTROYDESTROYDESTROYDESTROYDESTROY");
    super.onDestroy();
}

适配器:

public class PagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);

        this.fragments = fragments;

    }

    @Override
    public Fragment getItem(int position) {

        return this.fragments.get(position);

    }

    @Override
    public int getCount() {

        return this.fragments.size();

    }

}

我的一个片段剥离,但我commetned everyhting出这就是剥离,仍然does not工作...

One of my Fragments stripped but i commetned everyhting out thats stripped and still doesnt work...

public class MyFragment extends Fragment implements MyFragmentInterface, OnScrollListener {
...

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    handler = new Handler();    
    setHasOptionsMenu(true);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.w(TAG,"ATTACHATTACHATTACHATTACHATTACH");
    context = activity;
    if(context== null){
        Log.e("IS NULL", "NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL");
    }else{
        Log.d("IS NOT NULL", "NOTNOTNOTNOTNOTNOTNOTNOT");
    }

}

@Override
public void onActivityCreated(Bundle savedState) {
    super.onActivityCreated(savedState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.my_fragment,container, false);

    return v;
}


@Override
public void onResume(){
    super.onResume();
}

private void callService(){
    // do not call another service is already running
    if(startLoad || !canSet) return;
    // set flag
    startLoad = true;
    canSet = false;
    // show the bottom spinner
    addFooter();
    Intent intent = new Intent(context, MyService.class);
    intent.putExtra(MyService.STATUS_RECEIVER, resultReceiver);
    context.startService(intent);
}

private ResultReceiver resultReceiver = new ResultReceiver(null) {
    @Override
    protected void onReceiveResult(int resultCode, final Bundle resultData) {
        boolean isSet = false;
        if(resultData!=null)
        if(resultData.containsKey(MyService.STATUS_FINISHED_GET)){
            if(resultData.getBoolean(MyService.STATUS_FINISHED_GET)){
                removeFooter();
                startLoad = false;
                isSet = true;
            }
        }

        switch(resultCode){
        case MyService.STATUS_FINISHED: 
            stopSpinning();
            break;
        case SyncService.STATUS_RUNNING:
            break;
        case SyncService.STATUS_ERROR:
            break;
        }
    }
};

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.activity, menu);
}

@Override
public void onPause(){
    super.onPause();
}

public void onScroll(AbsListView arg0, int firstVisible, int visibleCount, int totalCount) {
    boolean loadMore = /* maybe add a padding */
        firstVisible + visibleCount >= totalCount;

    boolean away = firstVisible+ visibleCount <= totalCount - visibleCount;

    if(away){
        // startLoad can now be set again
        canSet = true;
    }

    if(loadMore) 

}

public void onScrollStateChanged(AbsListView arg0, int state) {
    switch(state){
    case OnScrollListener.SCROLL_STATE_FLING: 
        adapter.setLoad(false); 
        lastState = OnScrollListener.SCROLL_STATE_FLING;
        break;
    case OnScrollListener.SCROLL_STATE_IDLE: 
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_IDLE;
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
        break;
    }
}

@Override
public void onDetach(){
    super.onDetach();
    if(this.adapter!=null)
        this.adapter.clearContext();

    Log.w(TAG, "DETACHEDDETACHEDDETACHEDDETACHEDDETACHEDDETACHED");
}

public void update(final int id, String name) {
    if(name!=null){
        getActivity().getSupportActionBar().setTitle(name);
    }

}

}

当用户交互不同的片段和getActivity被返回null update方法被调用。下面是该方法的另一片段呼吁...

The update method is called when a user interacts with a different fragment and the getActivity is returning null. Here is the method the other fragment is calling...

((MyFragment) pagerAdapter.getItem(1)).update(id, name);

我相信,当应用程序被破坏然后重新创建刚刚起步的应用程序到默认的片段,而不是应用程序启动,然后viewpager导航到最后一个已知页面。这似乎很奇怪,不应该应用程序只加载到默认的片段?

I believe that when the app is destroyed then created again instead of just starting the app up to the default fragment the app starts up and then viewpager navigates to the last known page. This seems strange, shouldn't the app just load to the default fragment?

推荐答案

您正在运行到一个问题,因为你是实例化和保持的引用您的片段外 PagerAdapter.getItem ,并试图独立于ViewPager的使用这些引用。作为六翼天使说,你这样做有保证的片段已经被实例/在特定的时间加在ViewPager - 这应该被认为是一个实现细节。一个ViewPager做它的页面延迟加载;默认它仅加载当前页和一到左边和右边。

You are running into a problem because you are instantiating and keeping references to your fragments outside of PagerAdapter.getItem, and are trying to use those references independently of the ViewPager. As Seraph says, you do have guarantees that a fragment has been instantiated/added in a ViewPager at a particular time - this should be considered an implementation detail. A ViewPager does lazy loading of its pages; by default it only loads the current page, and the one to the left and right.

如果你把你的应用程序到背景中,已添加到碎片经理的片段会自动保存。即使您的应用程序被终止,此信息,当您重新启动您的应用程序恢复。

If you put your app into the background, the fragments that have been added to the fragment manager are saved automatically. Even if your app is killed, this information is restored when you relaunch your app.

现在假设您已经浏览了几页,碎片A,B和C。你知道,这些都被添加到片段经理。由于您使用的是 FragmentPagerAdapter ,而不是 FragmentStatePagerAdapter ,这些片段仍然会增加(但可能分离的),当你滚动其他网页。

Now consider that you have viewed a few pages, Fragments A, B and C. You know that these have been added to the fragment manager. Because you are using FragmentPagerAdapter and not FragmentStatePagerAdapter, these fragments will still be added (but potentially detached) when you scroll to other pages.

想想看,你那么后台的应用程序,然后它就会被杀死。当你回来时,机器人会记得你曾经有过的片段A,B和C的片段经理,所以他们重新创建为你,然后将它们相加。 但是,添加到片段经理的人现在不是那些你在你的片段列表中的活动。

Consider that you then background your application, and then it gets killed. When you come back, Android will remember that you used to have Fragments A, B and C in the fragment manager and so it recreates them for you and then adds them. However, the ones that are added to the fragment manager now are NOT the ones you have in your fragments list in your Activity.

在FragmentPagerAdapter不会尝试调用为getPosition 如果已经存在对特定页面位置添加一个片段。事实上,由于搭载Android重建的片段将永远不会被删除,你有没有希望通过调用替换为为getPosition 的。获取就可以了手感也pretty的难以获得引用它,因为它添加了标记,是未知的你。这是由设计;你是从与该视图寻呼机正在管理的碎片搞乱气馁。你应该执行所有操作,可以片段内,与该活动的通信,以及请求切换到一个特定的页上,如果有必要的。

The FragmentPagerAdapter will not try to call getPosition if there is already a fragment added for that particular page position. In fact, since the fragment recreated by Android will never be removed, you have no hope of replacing it with a call to getPosition. Getting a handle on it is also pretty difficult to obtain a reference to it because it was added with a tag that is unknown to you. This is by design; you are discouraged from messing with the fragments that the view pager is managing. You should be performing all your actions within a fragment, communicating with the activity, and requesting to switch to a particular page, if necessary.

现在,回到你的问题,缺少的活动。呼叫 pagerAdapter.getItem(1))。更新(ID,姓名)之后,这一切已经发生的回报,你的片段在你的列表中,这还有待于添加到片段经理,所以它不会有一个活动的参考。我愿意建议您更新的方法应该修改某些共享数据结构(可能由活动管理的),然后当你移动到特定的页面就可以在此基础上更新的数据绘制自身。

Now, back to your problem with the missing activity. Calling pagerAdapter.getItem(1)).update(id, name) after all of this has happened returns you the fragment in your list, which has yet to be added to the fragment manager, and so it will not have an Activity reference. I would that suggest your update method should modify some shared data structure (possibly managed by the activity), and then when you move to a particular page it can draw itself based on this updated data.

这篇关于支持FragmentPagerAdapter持有引用旧片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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