我有一个MainListActivity
,它显示一个ListFragment
,它使用RecyclerView
来显示项目网格。使用SyncAdapter
中onAttach
中的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
答案 0 :(得分:0)
在片段的onCreate方法中使用setRetainInstance(true)。
public void setRetainInstance(布尔值保留)
控制片段实例是否在Activity重新创建之间保留(例如,通过配置更改)。这只能与不在后堆栈中的片段一起使用。如果设置,则重新创建活动时片段的生命周期将略有不同:
- onDestroy()将不会被调用(但onDetach()仍会被调用,因为 该片段正在从其当前活动中分离出来。)
- onCreate(Bundle)将不会被调用,因为该片段没有被重新创建。
- onAttach(Activity)和onActivityCreated(Bundle)仍将被调用。