当屏幕旋转发生时,我一直面临着这个问题。我已经看到了堆栈溢出的所有类似帖子,但没有运气。
这是我的活动,有两个片段NEwsList和NewsDetails 单击列表中的项目时将调用NewsDetails片段。
public class MainActivity extends AppCompatActivity implements OnNewsItemClicked, PresenterLocator {
@Bind(R.id.news_list_fragment)
FrameLayout listFragmentContainer;
@Nullable
@Bind(R.id.news_details_fragment)
FrameLayout newsDetailsContainer;
private boolean isTablet;
private NewsScreenPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
isTablet = newsDetailsContainer == null ? false : true;
presenter = (NewsScreenPresenter) getLastCustomNonConfigurationInstance();
if (presenter == null) {
presenter = new NewsScreenPresenter(new NewsRetrofitGateway(), this);
}
if (savedInstanceState == null) {
attachListFragment();
}
}
private void attachListFragment() {
Fragment listFragment = new NewsListFragment();
Bundle bundle = new Bundle();
bundle.putBoolean(NewsListFragment.IS_TABLET, isTablet);
listFragment.setArguments(bundle);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.news_list_fragment, listFragment);
transaction.commit();
}
@Override
public Object onRetainCustomNonConfigurationInstance() {
return presenter;
}
@Override
public void onNewsItemClicked(String title, String summary, String picUrl, String storyUrl) {
if (!isFinishing()) {
Fragment fragment = new NewsDetailFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
fragment.setArguments(NewsDetailFragment.buildArguments(title, summary, picUrl, storyUrl));
if (!isTablet) {
transaction.add(R.id.news_list_fragment, fragment);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
} else {
transaction.replace(R.id.news_details_fragment, fragment);
}
transaction.commit();
}
}
@Override
public NewsScreenPresenter getPresenter() {
return presenter;
}}
NewsListFramgment
public class NewsListFragment extends Fragment implements NewsScreenView {
public static final String IS_TABLET = "is_tablet";
private NewsScreenPresenter presenter;
@Bind(R.id.progressBar)
LinearLayout progressBar;
@Bind(R.id.recycler_view)
RecyclerView recyclerView;
private boolean isTablet;
private PresenterLocator locator;
@Override
public void onAttach(Context context) {
super.onAttach(context);
locator = (PresenterLocator) context;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View listView = inflater.inflate(R.layout.new_list_layout, null);
ButterKnife.bind(this, listView);
return listView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
isTablet = getArguments().getBoolean(IS_TABLET);
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
presenter = locator.getPresenter();
presenter.onViewCreated(this);
}
@Override
public void showProgressBar() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
if (progressBar.getVisibility() == View.VISIBLE) {
progressBar.setVisibility(View.GONE);
}
}
@Override
public void populateNewsInList(final NewsResponseMapper news) {
NewsListAdapter adapter = new NewsListAdapter(news, new OnRecycleItemClick() {
@Override
public void onItemClick(int position) {
presenter.onItemClick(position);
}
});
recyclerView.setAdapter(adapter);
if (isTablet) {
presenter.onItemClick(0);
}
}
@Override
public void showError(String errorMsg) {
Toast.makeText(getActivity(), errorMsg, Toast.LENGTH_LONG).show();
}
interface OnRecycleItemClick {
void onItemClick(int position);
}
NewsDetialsFragment
public class NewsDetailFragment extends Fragment {
public static final String STORY_URL = "storyURL";
public static final String TITLE = "title";
public static final String SUMMARY = "summary";
public static final String IMAGE_URL = "imageURL";
private BrowserNavigation browserNavigation;
@Bind(R.id.title)
TextView titleView;
@Bind(R.id.summary_content)
TextView summaryView;
@Bind(R.id.news_image)
DraweeView imageView;
public static Bundle buildArguments(String title, String summary,
String picUrl, String storyUrl) {
Bundle bundle = new Bundle();
bundle.putString(TITLE, title);
bundle.putString(SUMMARY, summary);
bundle.putString(IMAGE_URL, picUrl);
bundle.putString(STORY_URL, storyUrl);
return bundle;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View detailsView = inflater.inflate(R.layout.activity_detail, null);
ButterKnife.bind(this, detailsView);
return detailsView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle extras = getArguments();
String storyURL = extras.getString(STORY_URL);
String title = extras.getString(TITLE);
String summary = extras.getString(SUMMARY);
String imageURL = extras.getString(IMAGE_URL);
browserNavigation = new BrowserNavigation(getActivity(), storyURL);
titleView.setText(title);
summaryView.setText(summary);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setImageRequest(ImageRequest.fromUri(Uri.parse(imageURL)))
.setOldController(imageView.getController()).build();
imageView.setController(draweeController);
}
@OnClick(R.id.full_story_link)
public void fullStoryClicked() {
browserNavigation.navigate();
}
通过查看代码,您可以理解我正在关注MVP架构,当我看到NewsListFragment并旋转设备时,我正在使用onRetianCustomNonConfiguration()回调将活动者保存在活动中,以免再次调用服务器再次获取新闻列表。 一切都按预期工作正常,但是在旋转之后,每当我尝试单击列表中的项目以显示DetailsFragment(onNewsItemClick())时,它就会崩溃并发生非法状态异常"无法在OnSavedInstanceState"之后执行此操作。
有人能指出我在这里犯的错误吗?
FATAL EXCEPTION: main
Process: news.agoda.com.technewssample, PID: 24160
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1493)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1511)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:638)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:617)
at news.agoda.com.sample.presentation.MainActivity.onNewsItemClicked(MainActivity.java:96)
at news.agoda.com.sample.NewsScreenPresenter.onItemClick(NewsScreenPresenter.java:55)
at news.agoda.com.sample.presentation.NewsListFragment$1.onItemClick(NewsListFragment.java:89)
at news.agoda.com.sample.presentation.NewsListAdapter$1.onClick(NewsListAdapter.java:76)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19888)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5276)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:911)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:706)