活动onDestroy-onCreate之后的片段中的ViewPager和Activity重新创建/持久化数据

时间:2013-02-15 09:47:28

标签: android android-fragments android-viewpager

我使用ViewPager编写了一个活动,该活动在执行AsyncTask后填充。每个TestDataObject都与相关的TestFragment相关联。当屏幕旋转时,应用程序会因NullPointerException内部onCreateView方法而崩溃。我认为这是因为ViewPager /适配器onSaveInstanceState方法,onCreateView尝试在数据不可用时加载AsyncTask数据之前恢复数据。

我只能if onCreateView代码,但它对我来说并不像是一个正确的解决方案,因为ViewPager中的碎片数量可能会有所不同,因此最终可能会执行不必​​要的工作:恢复更改的viewpager内容然后替换最初的。在这种情况下,onSaveInstanceState似乎过于有害。据推测,我可以扩展ViewPager或Adapter以取消保存程序 - 我发现它也很奇怪。

你有什么更好的建议吗?

public class MainActivity extends LoggerActivity {

    private ArrayList<TestDataObject> mDataObjects = new ArrayList<MainActivity.TestDataObject>();

    private ViewPager mViewPager;
    private TestFragmentAdapter mViewPagerAdapter;

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

        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPagerAdapter = new TestFragmentAdapter(
                getSupportFragmentManager(), mDataObjects);
        mViewPager.setAdapter(mViewPagerAdapter);
        new TestAsyncTask().execute();
    }

    private class TestAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            mDataObjects.add(new TestDataObject());
            mDataObjects.add(new TestDataObject());
            mDataObjects.add(new TestDataObject());
            mViewPagerAdapter.notifyDataSetChanged();

        }
    }

    public static class TestFragment extends Fragment {

        private TestDataObject mDataObject;

        public static TestFragment getInstance(TestDataObject obj) {
            TestFragment f = new TestFragment();
            f.mDataObject = obj;
            return f;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            // layout.find...
            mDataObject.toString();
            return inflater.inflate(R.layout.fragment_test, null, false);
        }

    }

    public static class TestFragmentAdapter extends FragmentStatePagerAdapter {

        private List<TestDataObject> mDataObjects;

        public TestFragmentAdapter(FragmentManager fm, List<TestDataObject> objs) {
            super(fm);
            mDataObjects = objs;
        }

        @Override
        public Fragment getItem(int position) {
            return TestFragment.getInstance(mDataObjects.get(position));
        }

        @Override
        public int getCount() {
            return mDataObjects == null ? 0 : mDataObjects.size();
        }

    }

    public static class TestDataObject {
    }
}

1 个答案:

答案 0 :(得分:0)

  

我相信这是因为ViewPager / Adapter onSaveInstanceState   方法。 onCreateView尝试在异步任务之前恢复数据   数据尚不可用时的dataload。

这不是正在发生的事情(我假设你在mDataObject.toString();得到了例外),即使AsyncTask即时完成其工作,仍然会抛出异常。第一次运行应用程序后,ViewPager将包含三个片段。当您转动手机时,Activity将被销毁并再次重新创建。 ViewPager将尝试重新创建其中的片段,但这次它将通过使用默认的空构造函数来实现(这就是为什么不应该使用非空构造函数来传递数据)。如您所见,第一次由适配器创建Fragment时,它将由您getInstance方法(也是您初始化mDataObject的唯一点)创建传递TestDataObject个对象。当ViewPager重新初始化其片段时,该字段也会被初始化。

如果TestDataObject可以放在Bundle中,那么您可以简单地调整getInstance方法将一些参数传递给您的片段(因此数据字段将在{{{}时初始化1}}将重新创建它们)。我相信你已经看到了:

ViewPager

另一种方法是将最小量的数据传递给public static TestFragment getInstance(TestDataObject obj) { TestFragment f = new TestFragment(); // f.mDataObject = obj; <- don't do this // if possible Bundle args = new Bundle(); args.put("data", obj); // only if obj can be put in a Bundle f.setArguments(args); return f; } private TestDataObject mDataObject; @Override public void onCreate(Bundle savedInstance) { mDataObject = getArguments().get("data"); // again, depends on your TestDataObject } (如上所述),这样它就有足够的信息在重新创建时重新创建数据。