片段在方向改变时被创建两次

时间:2018-07-24 02:24:32

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

我有一个MainListActivity,它显示一个ListFragment,它使用RecyclerView来显示项目网格。使用SyncAdapteronAttach中的ListFragment从REST-API提取项目。使用片段的onSavedInstanceState,我保存了recyclerviews当前的滚动位置,并在重新创建视图时检索了它。在MainListActivity中,我仅在savedinstantstate为空

时创建一个新片段。

根据生命周期,每当我旋转屏幕时,都会重新创建片段。但是我使用日志观察到该片段被重新创建了TWICE,并且释放了先前保存的状态。

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);
        }

}

ListFragment:

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

1 个答案:

答案 0 :(得分:0)

在片段的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)