Android 在方向更改时创建两次片段
我有一个Android 在方向更改时创建两次片段,android,android-fragments,android-activity,android-recyclerview,android-lifecycle,Android,Android Fragments,Android Activity,Android Recyclerview,Android Lifecycle,我有一个MainListActivity,它显示一个ListFragment,它使用RecyclerView来显示项目的网格。使用ListFragment的onAttach中的SyncAdapter从REST-API获取项目。使用片段的savedInstanceState上的,我正在保存recyclerviews当前的滚动位置,并在重新创建视图时检索它。在MainListActivity中,我仅在savedinstantstate为空时创建一个新片段 按照生命周期,每次我旋转屏幕时,片段都会被重
MainListActivity
,它显示一个ListFragment
,它使用RecyclerView
来显示项目的网格。使用ListFragment
的onAttach
中的SyncAdapter
从REST-API获取项目。使用片段的savedInstanceState上的,我正在保存recyclerviews当前的滚动位置,并在重新创建视图时检索它。在MainListActivity
中,我仅在savedinstantstate
为空时创建一个新片段
按照生命周期,每次我旋转屏幕时,片段都会被重新创建。但我使用日志观察到,片段被重新创建了两次,并且我失去了先前保存的on状态
主列表活动:
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);
}
}
在片段的onCreate方法中使用setRetainInstance(true)
公共void setRetainInstance(布尔保留)
控制是否在活动重新创建期间保留片段实例(例如从配置更改)。这只能用于不在后堆栈中的片段。如果设置,则重新创建活动时片段生命周期将略有不同:
- 不会调用onDestroy()(但仍然会调用onDetach(),因为
正在从当前活动中分离片段)
- 由于未重新创建片段,因此不会调用onCreate(Bundle)
- 仍将调用onAttach(活动)和onActivityCreated(捆绑)
可以考虑使用VIEW模型。它是为了解决这个问题而创建的。
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