在运行时构建的 Fragment 上始终为 null savedInstanceState(导航视图)

Posted

技术标签:

【中文标题】在运行时构建的 Fragment 上始终为 null savedInstanceState(导航视图)【英文标题】:always null savedInstanceState on Fragment built at runtime (navigation view) 【发布时间】:2016-06-13 06:11:36 【问题描述】:

我正在尝试使用一个 Activity 和与导航项一样多的 Fragment 构建一个 NavigationView: 第一个项目被点击——>第一个片段加载一个随机的远程图像; 第二个/第三个项目被点击——>其他片段被加载。 我的目标是,在切换回第一个项目时,显示已下载的图片,而不是获取新图片。

activity_main.xml

<android.support.v4.widget.DrawerLayout
(.....)
android:id="@+id/drawer_layout">

<!-- This LinearLayout represents the contents of the screen  -->
<LinearLayout
    android:layout_
    android:layout_
    android:orientation="vertical">

    <!-- The ActionBar displayed at the top -->
    <include
        layout="@layout/toolbar"
        android:layout_
        android:layout_ />

    <!-- The main content view where fragments are loaded -->
    <FrameLayout
        (......)
        android:id="@+id/flContent"/>
</LinearLayout>

<!-- The navigation drawer that comes from the left -->
<android.support.design.widget.NavigationView
    (.......)
    android:id="@+id/nvView" />

主活动

public class MainActivity extends AppCompatActivity 

Fragment homeFragment;

@Override
protected void onCreate(Bundle savedInstanceState) 
   super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //......
    setupDrawerContent(nvDrawer);
    if (findViewById(R.id.flContent) != null && savedInstanceState == null) 
       homeFragment = new HomeFragment();
       getSupportFragmentManager().beginTransaction().add(R.id.flContent, homeFragment, "homeFragment").commit();
    


@Override
protected void onSaveInstanceState(Bundle outState) 
    super.onSaveInstanceState(outState);
    getSupportFragmentManager().putFragment(outState, "homeFragment", homeFragment);


private  void setupDrawerContent(NavigationView navigationView) 
    navigationView.setNavigationItemSelectedListener(
            new NavigationView.OnNavigationItemSelectedListener() 
                @Override
                public boolean onNavigationItemSelected(MenuItem menuItem) 
                    selectDrawerItem(menuItem);
                    return true;
                
            
    );


public void selectDrawerItem(MenuItem menuItem) 
    // Create a new fragment and specify the item to show based on
    // position
    Fragment fragment = null;

    Class fragmentClass = null;
    switch(menuItem.getItemId()) 
        case R.id.nav_first_fragment:
            fragmentClass = HomeFragment.class;
            break;
        case R.id.nav_second_fragment:
            fragmentClass = SecondFragment.class;
            break;
        default:
            fragmentClass = HomeFragment.class;
    
    try 
        fragment = (Fragment) fragmentClass.newInstance();
     catch (Exception e) 
        e.printStackTrace();
    

    // Insert the fragment by replacing any existing fragment
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();

    // Highlight the selected item, update the title, and close the drawer
    menuItem.setChecked(true);
    setTitle(menuItem.getTitle());
    mDrawer.closeDrawers();
   

首页片段

    public class HomeFragment extends Fragment 


    private static final String TAG = "HomeFragment";

    public HomeFragment() 
    

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        super.onCreateView(inflater, container, savedInstanceState);
        // ......
        View fragmentView = inflater.inflate(R.layout.home_fragment, container, false);
        if (savedInstanceState == null) 
            // FETCH RANDOM IMAGE
        else 
            // RESTORE IT (but always null)
        
        return fragmentView;
    

    @Override
    public void onSaveInstanceState(Bundle outState) 
        super.onSaveInstanceState(outState);
        outState.putSerializable(/*SOME DATA*/);
    

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) 
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) 
            // ALWAYS NULL
        
    
 

我找到了this 的答案,但我不知道该怎么做,因为我只是引用了 FrameLayout。

跟踪生命周期方法我注意到 MainActivity 处于活动状态,因此它从不调用 onSaveInstanceState,而且我不知道如何在 HomeFragment 中使用 Bundle 来恢复 onCreateView 中的 savedInstanceState。 你有什么提示可以分享吗? 非常感谢

【问题讨论】:

【参考方案1】:

当您将一个片段替换为另一个片段时,前一个片段(被替换)将被销毁,并且其非静态成员变量中的所有数据都将丢失。

如果您想保留片段的图像,您可以使用位图缓存来存储图像,但这只有在为片段加载相同图像时才有效。如果您正在加载随机图像并希望在下次实例化相同的片段时加载相同的图像(因此您希望 Home 片段始终加载它在第一次实例化时加载的相同图像),那么您需要坚持数据。有几种方法可以做到这一点,您可以在 Home 片段中使用静态变量来保存图像的 URL,您可以将其存储在 SharedPreferences 中,您可以将其传递给 Activity,以便 Activity 将其传递回再次创建时的主页片段,依此类推。选择最适合您需求的解决方案。

【讨论】:

感谢您的帮助!因为我在很多讨论中强调了捆绑舞的重要性,所以我“肯定”会这样做……您给了我有价值的解决方案,我一定会详细探讨,我真的很感激!

以上是关于在运行时构建的 Fragment 上始终为 null savedInstanceState(导航视图)的主要内容,如果未能解决你的问题,请参考以下文章

我踩到的关于Fragment 状态的保存和恢复的坑

AWS Pinpoint:活动目标端点为 Nul

Android学习路线(二十)运用Fragment构建动态UI

从命令行重置 iOS 应用程序

request.FILES 在文件上传时始终为空

如何将列表视图中的数据从一个片段发送到另一个片段