安卓:活动意外破坏,空savedInstanceState [英] Android: Activities destroyed unexpectedly, null savedInstanceState

查看:91
本文介绍了安卓:活动意外破坏,空savedInstanceState的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不打算列出所有的参考我已经通过发布这之前阅读,但我广泛阅读的计算器和所有活动/片段生命周期的Andr​​oid开发者文档和维护国家类似的问题,并没有找到一个解决办法

下面是我的情况:

我有一个使用FragmentPagerAdapter主要活动(ImpulseActivity)。每个片段显示我是从服务器中检索数据的一个单独的列表。当pressing在ImpulseActivity的动作条的action_item,可以过滤来自服务器发送的数据。要做到这一点,ImpulseActivity启动一个单独的活动(FilterEventsActivity)。 FilterEventsActivity列出ImpulseActivity,因为它的父活动。当pressing在后退按钮在FilterEventsActivity,ImpulseActivity被重建(称为OnCreate中)与(捆绑savedInstanceState)。出于测试目的,我重写的onSaveInstanceState和放置假数据outState。需要注意的是这种情况对于每个从ImpulseActivity启动的活动

我的问题是:

什么是正确的设计模式,以prevent从需要重新加载在这种特殊情况下数据的每个片段?我想preFER不使用Singleton模式,因为我的片段其他活动重复使用。

如果需要相关的源$ C ​​$ C:

 公共类ImpulseActivity扩展FragmentActivity工具
    ActionBar.TabListener {

私人MapSearchFragment mSearchFragment;
私人BulletinFragment mBulletinFragment;

SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;

@覆盖
保护无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.impulse_activity);

    Log.v(ImpulseActivity,的onCreate+ savedInstanceState);

    最后的动作条动作条= getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    CategoryManager经理= CategoryManager.getManager();
    manager.setListener(本);
    manager.loadCategories();

    mSectionsPagerAdapter =新SectionsPagerAdapter(
            getSupportFragmentManager());

    mViewPager =(ViewPager)findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager
            .setOnPageChangeListener(新ViewPager.SimpleOnPageChangeListener(){
                @覆盖
                公共无效onPageSelected(INT位置){
                    actionBar.setSelectedNavigationItem(位置);
                }
            });

    的for(int i = 0; I< mSectionsPagerAdapter.getCount();我++){
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(I))
                .setTabListener(本));
    }
}

@覆盖
公共无效的onSaveInstanceState(包outState){
    super.onSaveInstanceState(outState);
    outState.putDouble(你好,1.02);
}


@覆盖
公共布尔onCreateOptionsMenu(功能菜单){
    MenuInflater充气= getMenuInflater();
    inflater.inflate(R.menu.impulse_activity_actions,菜单);
    返回super.onCreateOptionsMenu(菜单);
}

@覆盖
公共布尔onOptionsItemSelected(菜单项项){
    INT的id = item.getItemId();
    如果(ID == R.id.action_create){
        返回true;
    }
    如果(ID == R.id.action_filter){
        意向意图=新的意图(这一点,FilterEventsActivity.class);
        startActivity(意向);
        返回true;
    }
    返回super.onOptionsItemSelected(项目);
}

@覆盖
公共无效onTabSelected(ActionBar.Tab选项卡,FragmentTransaction fragmentTransaction){
    INT位置= tab.getPosition();
    mViewPager.setCurrentItem(位置,真正的);
}

@覆盖
公共无效onEventListClick(事件e){
    意图mIntent =新的意图(这一点,EventActivity.class);
    捆绑mBundle =新包();
    mBundle.putSerializable(EventDetailsFragment.Event_Key,E);
    mIntent.putExtras(mBundle);
    startActivity(mIntent);
}

公共类SectionsPagerAdapter扩展FragmentPagerAdapter {

    公共SectionsPagerAdapter(FragmentManager FM){
        超(FM);
    }

    @覆盖
    公共片段的getItem(INT位置){

        片段片段
        开关(位置){
            情况下0:
                如果(mBulletinFragment!= NULL){
                    片段= mBulletinFragment;
                } 其他 {
                    片段=新BulletinFragment();
                    mBulletinFragment =(BulletinFragment)片段;
                }
                打破;
            情况1:
                片段=新MapSearchFragment();
                mSearchFragment =(MapSearchFragment)片段;
                打破;
            案例2:
                片段=新MyEventsFragment();
                打破;
            默认:
                片段=新BulletinFragment();
                打破;
        }
        捆绑的args =新包();
        fragment.setArguments(参数);
        返回片段;
    }

    @覆盖
    公众诠释getCount将(){
        //显示3总页​​数。
        返回3;
    }

    @覆盖
    公共CharSequence的getPageTitle(INT位置){
        区域设置L = Locale.getDefault();
        开关(位置){
            情况下0:
                返回公告;
            情况1:
                返回地图;
            案例2:
                回到我的活动;
            默认:
                返回测试;
        }
    }
}
}
 

AndroidManifest.xml中

 <活动
        机器人:Home.ImpulseActivityNAME =
        机器人:标签=@字符串/ APP_NAME>
        <意向滤光器>
            <作用机器人:名称=android.intent.action.MAIN/>

            <类机器人:名称=android.intent.category.LAUNCHER/>
        &所述; /意图滤光器>
    < /活性GT;
    <活动
        机器人:名称=。Event.EventActivity
        机器人:标签=@字符串/ title_activity_event
        机器人:parentActivityName =Home.ImpulseActivity。>
        &所述;元数据
            机器人:名称=android.support.PARENT_ACTIVITY
            Home.ImpulseActivity:机器人值= />
    < /活性GT;
 

解决方案

虽然这个问题提到片段,这个问题实际上是向上导航。

长达导航不能完全按照人们所期望的标准工作之外的活动的缺省实现。特别是,当父活动有 launchMode =标准(默认值),pressing向上按钮的创建一个新的实例的它,不能回到previous之一。

有用于解决该问题的两种选择:

  1. 更改 launchMode ImpulseActivity singleTop 的清单中。
  2. 覆盖home键操作以启动与 FLAG_ACTIVITY_CLEAR_TOP 标记的意图。例如,在 EventActivity.onOptionsItemSelected()

     如果(ID == android.R.id.home)
    {
        意向意图= NavUtils.getParentActivityIntent(本);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        NavUtils.navigateUpTo(这一点,意图);
        返回true;
    }
     

无论这些都将带给你的老年活动堆栈的顶部。

I am not going to list every reference I've read through before posting this, but I have extensively read similar questions on stackoverflow and all of the android developer docs on activity/fragment lifecycles and maintaining state and have not found a solution.

Here is my scenario:

I have a main activity (ImpulseActivity) that uses a FragmentPagerAdapter. Each fragment displays a separate list of data that I am retrieving from the server. When pressing an action_item in ImpulseActivity's actionbar, you can filter data sent from the server. To accomplish this, ImpulseActivity launches a separate activity (FilterEventsActivity). FilterEventsActivity lists ImpulseActivity as it's parent activity. When pressing the back button on FilterEventsActivity, ImpulseActivity is recreated (OnCreate called) with a null (Bundle savedInstanceState). For testing purposes, I am overriding OnSaveInstanceState and placing fake data in outState. Note that this happens for every activity launched from ImpulseActivity.

My question is:

What is the proper design paradigm to prevent each fragment from needing to reload data in this particular situation? I would prefer not to use the Singleton pattern since my fragments are reused in other activities.

Relevant source code if needed:

public class ImpulseActivity extends FragmentActivity implements
    ActionBar.TabListener {

private MapSearchFragment mSearchFragment;
private BulletinFragment mBulletinFragment;

SectionsPagerAdapter mSectionsPagerAdapter;
ViewPager mViewPager;

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

    Log.v("ImpulseActivity", "onCreate " + savedInstanceState);

    final ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    CategoryManager manager = CategoryManager.getManager();
    manager.setListener(this);
    manager.loadCategories();

    mSectionsPagerAdapter = new SectionsPagerAdapter(
            getSupportFragmentManager());

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

    for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
        actionBar.addTab(actionBar.newTab()
                .setText(mSectionsPagerAdapter.getPageTitle(i))
                .setTabListener(this));
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putDouble("Hello", 1.02);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.impulse_activity_actions, menu);
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.action_create) {
        return true;
    }
    if (id == R.id.action_filter) {
        Intent intent = new Intent(this, FilterEventsActivity.class);
        startActivity(intent);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    int position = tab.getPosition();
    mViewPager.setCurrentItem(position, true);
}

@Override
public void onEventListClick(Event e) {
    Intent mIntent = new Intent(this, EventActivity.class);
    Bundle mBundle = new Bundle();
    mBundle.putSerializable(EventDetailsFragment.Event_Key, e);
    mIntent.putExtras(mBundle);
    startActivity(mIntent);
}

public class SectionsPagerAdapter extends FragmentPagerAdapter {

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment;
        switch(position) {
            case 0:
                if (mBulletinFragment != null) {
                    fragment = mBulletinFragment;
                } else {
                    fragment = new BulletinFragment();
                    mBulletinFragment = (BulletinFragment) fragment;
                }
                break;
            case 1:
                fragment = new MapSearchFragment();
                mSearchFragment = (MapSearchFragment) fragment;
                break;
            case 2:
                fragment = new MyEventsFragment();
                break;
            default:
                fragment = new BulletinFragment();
                break;
        }
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getCount() {
        // Show 3 total pages.
        return 3;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        Locale l = Locale.getDefault();
        switch (position) {
            case 0:
                return "Bulletin";
            case 1:
                return "Map";
            case 2:
                return "My Events";
            default:
                return "Test";
        }
    }
}
}

AndroidManifest.xml

<activity
        android:name=".Home.ImpulseActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".Event.EventActivity"
        android:label="@string/title_activity_event"
        android:parentActivityName=".Home.ImpulseActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".Home.ImpulseActivity" />
    </activity>

解决方案

Although the question mentions Fragments, the problem is actually with up navigation.

The default implementation for up navigation doesn't work exactly as one would expect for standard activties. In particular, when the parent activity has launchMode="standard" (the default), pressing the up button will create a new instance of it, not return to the previous one.

There are two alternatives for solving this problem:

  1. Changing the launchMode of ImpulseActivity to singleTop in the Manifest.
  2. Overriding the home button action to launch the intent with the FLAG_ACTIVITY_CLEAR_TOP flag. For example, in EventActivity.onOptionsItemSelected():

    if (id == android.R.id.home)
    {
        Intent intent = NavUtils.getParentActivityIntent(this);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        NavUtils.navigateUpTo(this, intent);
        return true;
    }
    

Either of these will bring your old activity to the top of the stack.

这篇关于安卓:活动意外破坏,空savedInstanceState的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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