【问题标题】:Fragment gets created twice on orientation change片段在方向更改时创建两次
【发布时间】:2018-07-24 02:24:31
【问题描述】:

我有一个MainListActivity,它显示一个ListFragment,它使用RecyclerView 来显示项目网格。这些项目是使用onAttach 中的SyncAdapter 中的ListFragment 从REST-API 获取的。使用片段的onSavedInstanceState,我正在保存 recyclerviews 当前滚动位置并在重新创建视图时检索它。在MainListActivity 中,如果savedinstantstate 为空,我只会创建一个新片段

根据生命周期,每次我旋转屏幕时,都会重新创建 Fragment。但是我使用日志观察到片段被重新创建了两次,并且我失去了之前保存的状态。

MainListActivity:

public class MainListActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

        ....
        ....

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setupWindowAnimations();
            ButterKnife.bind(this);
            setContentView(R.layout.activity_main_list);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
            getSupportActionBar().setDisplayShowTitleEnabled(false);
            toolbar.setTitle(R.string.state_prompt);

            if(savedInstanceState == null) {
                Log.e(TAG, "onCreate: HERE 1");
                listFragment = (ListFragment) getSupportFragmentManager().findFragmentById(R.id.list_container);
                if (listFragment == null) {
                    Log.e(TAG, "onCreate: HERE 1");
                    listFragment = ListFragment.newInstance(this, state);
                    getSupportFragmentManager().beginTransaction()
                            .add(R.id.list_container, listFragment)
                            .commit();
                }
            }

        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main_list, menu);
            MenuItem item = menu.findItem(R.id.spinner);
            spinner = (Spinner) MenuItemCompat.getActionView(item);
            item.setTitle(getResources().getString(R.string.state_prompt));
            spinner.setDropDownWidth(130);
            spinner.setPopupBackgroundResource(R.color.primaryText);
            ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                    R.array.state_arrays, R.layout.spinner_item);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spinner.setAdapter(adapter);
            spinner.setOnItemSelectedListener(this);
            return true;
        }

        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long l) {
            state = String.valueOf(spinner.getSelectedItem());
            listFragment = ListFragment.newInstance(this, state);
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.list_container, listFragment)
                    .commit();
         }


        @Override
        protected void onSaveInstanceState(Bundle outState) {
            outState.putString(SELECTED_STATE, state);
            super.onSaveInstanceState(outState);
        }

}

列表片段:

public class ListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{

    static int currentVisiblePosition = 0;

    public ListFragment() {
    }

    public static ListFragment newInstance(Context context, String state) {
        Bundle arguments = new Bundle();
        ListFragment fragment = new ListFragment();
        arguments.putString(SELECTED_STATE, state);
        fragment.setArguments(arguments);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        ParkSyncAdapter.performSync(state, max_article);
        MobileAds.initialize(getActivity(), "ca-app-pub-1510923228147176~5607247189");
        Log.e(TAG, "onAttach: HERE");
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null) {
            currentVisiblePosition = savedInstanceState.getInt(LIST_STATE_KEY);
        }
        getLoaderManager().initLoader(LOADER_ID, null, this);

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_fragment, container, false);
        mAdView = new AdView(getActivity());
        mAdView.setAdUnitId("ca-app-pub-1510923228147176/1177047580");
        mAdView.setAdSize(AdSize.BANNER);
        LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.admob_ll);
        linearLayout.addView(mAdView);
        AdRequest adRequest = new AdRequest.Builder().addTestDevice(AdRequest.DEVICE_ID_EMULATOR).addTestDevice("Somestring").build();
        mAdView.loadAd(adRequest);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ButterKnife.bind(this, view);
        adapter = new ListAdapter(this, getContext());
        if (idlingResource != null) {
            idlingResource.setIdleState(true);
        }
        progressBar.setVisibility(View.VISIBLE);
        recyclerView.setAdapter(adapter);
        if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            layoutManager = new GridLayoutManager(getActivity(), 2);
            recyclerView.setLayoutManager(layoutManager);
        } else {
            layoutManager = new GridLayoutManager(getActivity(), 4);
            recyclerView.setLayoutManager(layoutManager);
        }
        Log.e(TAG, "onViewCreated: POSITION: "+currentVisiblePosition);
        recyclerView.getLayoutManager().scrollToPosition(currentVisiblePosition);
        currentVisiblePosition = 0;
        View detailsView = getActivity().findViewById(R.id.details);
        mDualPane = detailsView != null && detailsView.getVisibility() == View.VISIBLE;

    }



    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        currentVisiblePosition = ((GridLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
        Log.e(TAG, "onSaveInstanceState: POSITION: "+currentVisiblePosition);
        outState.putInt(LIST_STATE_KEY, currentVisiblePosition);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: HERE");
        super.onDestroy();
    }

    @NonNull
    @Override
    public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
        uri = ParkContract.ParkEntry.CONTENT_URI_PARKS;
        return new CursorLoader(getActivity(), uri, PROJECTION, null, null, null);
    }

    @Override
    public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
        adapter.swapCursor(data);
        recyclerView.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onLoaderReset(@NonNull Loader<Cursor> loader) {
        if (adapter != null) {
            adapter.swapCursor(null);
        }
    }
}

日志片段:

// ****Fragment created for the 1st time
    07-23 19:03:15.674 E/ListFragment: onAttach: HERE                    
    07-23 19:03:15.898 E/ListFragment: onViewCreated: POSITION: 0
// ****Not sure why Fragment gets recreated here 2nd time
    07-23 19:03:17.292 E/ListFragment: onAttach: HERE
    07-23 19:03:17.321 E/ListFragment: onDestroy: HERE
    07-23 19:03:17.403 E/ListFragment: onViewCreated: POSITION: 0
// ****Orientation change, saving RecyclerView's position
    07-23 19:03:33.557 E/ListFragment: onSaveInstanceState: POSITION: 6
    07-23 19:03:33.612 E/ListFragment: onDestroy: HERE
    07-23 19:03:33.677 E/ListFragment: onAttach: HERE
    07-23 19:03:33.805 E/stetho: Could not start Stetho server: main
// ****Position correctly retrieved
    07-23 19:03:33.859 E/ListFragment: onViewCreated: POSITION: 6
// ****Again,  Fragment gets recreated here 2nd time loosing the previously saved position
    07-23 19:03:34.394 E/ListFragment: onAttach: HERE
    07-23 19:03:34.406 E/ListFragment: onDestroy: HERE
    07-23 19:03:34.471 E/ListFragment: onViewCreated: POSITION: 0

【问题讨论】:

标签: android android-fragments android-activity android-recyclerview android-lifecycle


【解决方案1】:

在片段的 onCreate 方法中使用 setRetainInstance(true)。

public void setRetainInstance(布尔保留)

控制是否在重新创建 Activity 时保留片段实例(例如来自配置更改)。这只能与不在后台堆栈中的片段一起使用。如果设置,则在重新创建活动时片段生命周期将略有不同:

  • onDestroy() 不会被调用(但 onDetach() 仍然会被调用,因为 该片段正在与其当前活动分离)。
  • onCreate(Bundle) 不会被调用,因为片段没有被重新创建。
  • onAttach(Activity) 和 onActivityCreated(Bundle) 仍将被调用。

https://developer.android.com/reference/android/support/v4/app/Fragment.html#setRetainInstance(boolean)

【讨论】:

    猜你喜欢
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多