如何避免一个IllegalStateException如果我需要添加onNewIntent(一片段)或运行时更改后? [英] How can I avoid an IllegalStateException if I need to add a Fragment in onNewIntent() or after a run-time change?

查看:212
本文介绍了如何避免一个IllegalStateException如果我需要添加onNewIntent(一片段)或运行时更改后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很清楚的一个IllegalStateException是什么,为什么会发生,当你试图经过实例状态已保存到提交FragmentTransactions。我已经通过大部分关于这一主题的流行问题#1阅读以及的博客文章

我在其中,而应用程序在等待我创建了一个片段,显示自定义进度微调特定方案对一些搜索结果进来,所以我的搜索活动是singleTop模式下运行,并且依赖于 onNewIntent()来执行搜索和显示的微调。这一切工作正常,但是当运行时更改进来(如方向变化)失败。如果我试图改变方向之后,除去微调片段的进展,或者语音搜索后加入微调时,我会得到一个IllegalStateException。我的设置是这样的:

  @覆盖
保护无效onNewIntent(意向意图){
    如果(intent.getAction()。等于(Intent.ACTION_SEARCH)){
        performSearch(intent.getStringExtra(SearchManager.QUERY));
    }
}

performSearch()方法将请求发送到我的服务器,然后添加进度微调片段像这样...

 私人无效showProgressSpinner(){
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction交易= fragmentManager.beginTransaction();
    transaction.setCustomAnimations(R.anim.fragment_fade_in,R.anim.fragment_fade_out);
    ProgressFragment微调= ProgressFragment.newInstance();
    transaction.add(R.id.searchContainer,微调,微调);
    器transaction.commit();
}

然后,当搜索结果通过异步回调进来,我删除进度微调片段像这样...

 私人无效dismissProgressSpinner(){
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction交易= fragmentManager.beginTransaction();
    transaction.setCustomAnimations(R.anim.fragment_fade_in,R.anim.fragment_fade_out);
    ProgressFragment微调=(ProgressFragment)fragmentManager.findFragmentByTag(微调);
    如果(微调!= NULL){
        transaction.remove(微调);
    }
    器transaction.commit();
}

如果改变方向时进来在显示微调片段的进展,我得到的IllegalStateException异常时,搜索结果中返回,我尝试删除微调片段。据亚历克斯·洛克伍德,把FragmentTransaction在 onPostResume()能有所帮助,因为你都保证届时恢复状态。这确实是工作,但我需要从搜索结果中删除片段在我的异步回调,不能当活动恢复。

我的问题是,我怎么能犯的状态改变之后,但在我的异步回调此片段的交易?我已经尝试过使用 commitAllowingStateLoss(),但我仍然得到例外,因为我的微调片段仍引用旧被毁活动。什么是处理这个问题的最佳方式?


解决方案

  

我使用commitAllowingStateLoss()尝试,但我仍然得到例外,因为我的微调片段仍引用旧销毁活动。


您片段配置的变化,即后重建。用户后有旋转屏幕 - 您的微调片段将被销毁并重新创建,并onAttach后,将引用新的活动实例。此外这一切过程都是由机器人完成在单个消息UI线程,所以没有机会,你的异步操作的回调(这也应执行对UI线程)在中间被执行。

我假设在这里你没有创建内部ProgressFragment一些地方参考的活动。

您可以编写额外的逻辑,将确保你的提交被称为有效的时刻。 IE浏览器。在您的活动ONSTART设置一些静态布尔allowCommit为真,并在它的onPause设置为false。同时添加一些静态变量,searchWasFinished,并在异步回调检查是否allowCommit为真,如果是的话立即删除微调,如果没有则只能设置searchWasFinished为true。里面你Activity.onStart检查,如果searchWasFinished ==真,如果是这样,然后删除与承诺片段。这仅仅是一个想法,可能更多的逻辑将必须把在它

I'm well aware of what an IllegalStateException is and why it happens when you are trying to commit FragmentTransactions after instance state has been saved. I've read through most of the popular Stackoverflow questions on the subject as well as "The Blog Post."

I have a particular scenario in which I've created a Fragment to display a custom progress spinner while the app is waiting for some search results to come in. So my search Activity is running in singleTop mode and relies on onNewIntent() to perform the search and display the spinner. This all works fine, but fails when run-time changes come in (like orientation changes). I'll get an IllegalStateException if I try removing the progress spinner Fragment after an orientation change, or when adding the spinner after a voice search. My setup looks like this:

@Override
protected void onNewIntent(Intent intent) {
    if(intent.getAction().equals(Intent.ACTION_SEARCH)) {
        performSearch(intent.getStringExtra(SearchManager.QUERY));
    } 
}

The performSearch() method sends the request to my server and then adds the progress spinner Fragment like this...

private void showProgressSpinner() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.setCustomAnimations(R.anim.fragment_fade_in, R.anim.fragment_fade_out);
    ProgressFragment spinner = ProgressFragment.newInstance();
    transaction.add(R.id.searchContainer, spinner, "spinner");
    transaction.commit();
}

Then when the search results come in through an asynchronous callback, I remove the progress spinner Fragment like this...

private void dismissProgressSpinner() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.setCustomAnimations(R.anim.fragment_fade_in, R.anim.fragment_fade_out);
    ProgressFragment spinner = (ProgressFragment) fragmentManager.findFragmentByTag("spinner");
    if(spinner != null) {
        transaction.remove(spinner);
    }
    transaction.commit();
}

If an orientation change comes in while the progress spinner Fragment is being displayed, I get the IllegalStateException when the search results return and I try to remove the spinner Fragment. According to Alex Lockwood, putting the FragmentTransaction in onPostResume() can help, since you are guaranteed to have the state restored by then. This indeed works, but I need to remove the Fragment in my asynchronous callback from the search results, not when the Activity resumes.

So my question is, how can I commit this Fragment transaction after a state change, but within my async callback? I've tried using commitAllowingStateLoss() but I still get the exception because my spinner Fragment is still referencing the old destroyed Activity. What's the best way to handle this?

解决方案

I've tried using commitAllowingStateLoss() but I still get the exception because my spinner Fragment is still referencing the old destroyed Activity.

your fragment was recreated after config change, ie. after user have rotated screen - your spinner fragment will be destroyed and recreated, and after onAttach it will reference new activity instance. Also all of this process is done by android on UI thread in single message, so there is no chance that your async operation callback (which should execute also on UI thread) gets executed in the middle.

I assume here you are not creating some local reference to activity inside ProgressFragment.

You could write additional logic that would make sure your commit is called in valid moment. ie. in your activity onStart set some static boolean allowCommit to true, and in onPause set it to false. Also add some static variable, searchWasFinished, and in your async callback check if allowCommit is true if so then immediately remove spinner, if not then only set searchWasFinished to true. Inside your Activity.onStart check if searchWasFinished==true and if so then remove fragment with commit. This is just an idea, probably more logic would have to be put in it.

这篇关于如何避免一个IllegalStateException如果我需要添加onNewIntent(一片段)或运行时更改后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆